从swift中的名称中获取属性的类型/类

时间:2015-04-05 11:01:19

标签: swift reflection

让我说我有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)

5 个答案:

答案 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
}