让我说我有class
:
class Node {
var value: String
var children: [Node]?
}
如果我有一个属性的名称(例如"children"
),我该如何获得它的类型? (在这种情况下为[Node]?
)
我想像下面这样的全局函数可以解决我的需求:
func typeOfPropertyWithName(name: String, ofClass: AnyClass) -> AnyClass? {
//???
}
// Example usage:
var arrayOfNodesClass = typeOfPropertyWithName("children", Node.self)
答案 0 :(得分:8)
Swift 2 (注意:反思改变了):
import Foundation
enum PropertyTypes:String
{
case OptionalInt = "Optional<Int>"
case Int = "Int"
case OptionalString = "Optional<String>"
case String = "String"
//...
}
extension NSObject{
//returns the property type
func getTypeOfProperty(name:String)->String?
{
let type: Mirror = Mirror(reflecting:self)
for child in type.children {
if child.label! == name
{
return String(child.value.dynamicType)
}
}
return nil
}
//Property Type Comparison
func propertyIsOfType(propertyName:String, type:PropertyTypes)->Bool
{
if getTypeOfProperty(propertyName) == type.rawValue
{
return true
}
return false
}
}
自定义类:
class Person : NSObject {
var id:Int?
var name : String?
var email : String?
var password : String?
var child:Person?
}
获取“child”属性的类型:
let person = Person()
let type = person.getTypeOfProperty("child")
print(type!) //-> Optional<Person>
属性类型检查:
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalInt) ) //--> false
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalString) //--> true
或
if person.propertyIsOfType("email", type: PropertyTypes.OptionalString)
{
//true -> do something
}
else
{
//false -> do something
}
答案 1 :(得分:3)
使用全局reflect()
函数在Swift中实现反射。将某种类型的实例传递给reflect()
时,它会返回MirrorType
,其中包含一系列属性,可让您分析实例:
var value: Any { get } var valueType: Any.Type { get } var objectIdentifier: ObjectIdentifier? { get } var count: Int { get } var summary: String { get } var quickLookObject: QuickLookObject? { get } var disposition: MirrorDisposition { get } subscript(i: Int) -> (String, MirrorType) { get }
答案 2 :(得分:1)
这似乎有效:
func getTypeOfVariableWithName(name: String, inInstance instance: Any) -> String? {
let mirror = reflect(instance)
var variableCollection = [String: MirrorType]()
for item in 0..<mirror.count {
variableCollection[mirror[item].0] = mirror[item].1
}
if let type = variableCollection[name] {
let longName = _stdlib_getDemangledTypeName(type.value)
let shortName = split(longName, { $0 == "."}).last
return shortName ?? longName
}
return nil
}
以下是SwiftStub上的一些示例代码。
可选值的结果仅为"Optional"
数组的结果仅为"Array"
词典的结果仅为"Dictionary"
。
我不确定是否可以提取它是什么类型的可选/数组/字典。但我想这也是使用泛型的自定义数据结构的情况。
答案 3 :(得分:1)
基于@PeterKreinz回答我需要能够检查继承属性的类型,所以在上面的代码中添加了一点:
extension NSObject {
// Returns the property type
func getTypeOfProperty (name: String) -> String? {
var type: Mirror = Mirror(reflecting: self)
for child in type.children {
if child.label! == name {
return String(child.value.dynamicType)
}
}
while let parent = type.superclassMirror() {
for child in parent.children {
if child.label! == name {
return String(child.value.dynamicType)
}
}
type = parent
}
return nil
}
}
希望这可以帮助某人。
Swift 3更新:
// Extends NSObject to add a function which returns property type
extension NSObject {
// Returns the property type
func getTypeOfProperty (_ name: String) -> String? {
var type: Mirror = Mirror(reflecting: self)
for child in type.children {
if child.label! == name {
return String(describing: type(of: child.value))
}
}
while let parent = type.superclassMirror {
for child in parent.children {
if child.label! == name {
return String(describing: type(of: child.value))
}
}
type = parent
}
return nil
}
}
答案 4 :(得分:0)
@ peter-kreinz使用Swift的类Mirror
提供的解决方案可以很好地工作,当你有一个类的实例,并想知道属性的类型。但是,如果要在没有实例的情况下检查类的属性,您可能会对我的解决方案感兴趣。
我有一个解决方案,可以找到任何继承自NSObject
的类的属性的名称和类型。
我在StackOverflow here上写了一个冗长的解释,我的项目可用here on Github,
简而言之,你可以做这样的事情(但实际上是检查代码Github):
public class func getTypesOfProperties(inClass clazz: NSObject.Type) -> Dictionary<String, Any>? {
var count = UInt32()
guard let properties = class_copyPropertyList(clazz, &count) else { return nil }
var types: Dictionary<String, Any> = [:]
for i in 0..<Int(count) {
guard let property: objc_property_t = properties[i], let name = getNameOf(property: property) else { continue }
let type = getTypeOf(property: property)
types[name] = type
}
free(properties)
return types
}