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

时间:2020-12-17 23:38:08

Lets say I have this class:

让我们说我有这个课程:

class Node {
    var value: String
    var children: [Node]?
}

If I have the name of one of its properties (for example "children") how can I get its type? (In this case [Node]?)

如果我有一个属性的名称(例如“children”),我该如何获得它的类型? (在这种情况下[节点]?)

I imagine having a global function like below will solve my needs:

我想像下面这样的全局函数可以解决我的需求:

func typeOfPropertyWithName(name: String, ofClass: AnyClass) -> AnyClass? {
    //???
}

// Example usage:
var arrayOfNodesClass = typeOfPropertyWithName("children", Node.self)

5 个解决方案

#1


8  

Swift 2 (Note: Reflection changed):

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

custom class:

自定义类:

class Person : NSObject {
    var id:Int?
    var name : String?
    var email : String?
    var password : String?
    var child:Person?
}

get the type of the "child" property:

获取“子”属性的类型:

let person = Person()
let type = person.getTypeOfProperty("child")
print(type!) //-> Optional<Person>

property type checking:

物业类型检查:

print( person.propertyIsOfType("email", type: PropertyTypes.OptionalInt) ) //--> false
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalString) //--> true

or

要么

if person.propertyIsOfType("email", type: PropertyTypes.OptionalString)
{
    //true -> do something
}
else
{
    //false -> do something
}

#2


3  

Reflection is achieved in Swift using the global reflect() function. When passing an instance of some type to reflect() it returns a MirrorType, which has a range of properties allowing you to analyze your instance:

使用全局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 }

#3


1  

This seems to work:

这似乎有效:

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
}

Here's some example code on SwiftStub.

这是SwiftStub上的一些示例代码。


Edit:

The result for optional values is only "Optional".
The result for arrays is only "Array".
The result for dictionaries is only "Dictionary".

可选值的结果仅为“可选”。数组的结果只是“数组”。词典的结果只是“词典”。

I'm not sure if it is possible to extract what kind of optional/array/dictionary it is. But I guess this would also be the case for custom data structures using generics.

我不确定是否可以提取它是什么类型的可选/数组/字典。但我想这也是使用泛型的自定义数据结构的情况。

#4


1  

Building on @PeterKreinz answer I needed to be able to check types of inherited properties as well so added a little to his above code:

在@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
    }

}

Hope this may help someone.

希望这可以帮助某人。

Swift 3 update:

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

#5


0  

The solution provided by @peter-kreinz using Swift's class Mirror works beautifully when you have an instance of a class, and want to know the types of the properties. However if you want to inspect the properties of a class without having an instance of it you might be interested in my solution.

@ peter-kreinz使用Swift的类Mirror提供的解决方案可以很好地工作,当你有一个类的实例,并想知道属性的类型。但是,如果要在没有实例的情况下检查类的属性,您可能会对我的解决方案感兴趣。

I have a solution that finds the name and type of a property given any class that inherits from NSObject.

我有一个解决方案,找到任何继承自NSObject的类的属性的名称和类型。

I wrote a lengthy explanation on * here, and my project is available here on Github,

我在这里写了一篇关于*的冗长解释,我的项目可以在Github上找到,

In short you can do something like this (but really check out the code 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
}

#1


8  

Swift 2 (Note: Reflection changed):

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

custom class:

自定义类:

class Person : NSObject {
    var id:Int?
    var name : String?
    var email : String?
    var password : String?
    var child:Person?
}

get the type of the "child" property:

获取“子”属性的类型:

let person = Person()
let type = person.getTypeOfProperty("child")
print(type!) //-> Optional<Person>

property type checking:

物业类型检查:

print( person.propertyIsOfType("email", type: PropertyTypes.OptionalInt) ) //--> false
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalString) //--> true

or

要么

if person.propertyIsOfType("email", type: PropertyTypes.OptionalString)
{
    //true -> do something
}
else
{
    //false -> do something
}

#2


3  

Reflection is achieved in Swift using the global reflect() function. When passing an instance of some type to reflect() it returns a MirrorType, which has a range of properties allowing you to analyze your instance:

使用全局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 }

#3


1  

This seems to work:

这似乎有效:

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
}

Here's some example code on SwiftStub.

这是SwiftStub上的一些示例代码。


Edit:

The result for optional values is only "Optional".
The result for arrays is only "Array".
The result for dictionaries is only "Dictionary".

可选值的结果仅为“可选”。数组的结果只是“数组”。词典的结果只是“词典”。

I'm not sure if it is possible to extract what kind of optional/array/dictionary it is. But I guess this would also be the case for custom data structures using generics.

我不确定是否可以提取它是什么类型的可选/数组/字典。但我想这也是使用泛型的自定义数据结构的情况。

#4


1  

Building on @PeterKreinz answer I needed to be able to check types of inherited properties as well so added a little to his above code:

在@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
    }

}

Hope this may help someone.

希望这可以帮助某人。

Swift 3 update:

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

#5


0  

The solution provided by @peter-kreinz using Swift's class Mirror works beautifully when you have an instance of a class, and want to know the types of the properties. However if you want to inspect the properties of a class without having an instance of it you might be interested in my solution.

@ peter-kreinz使用Swift的类Mirror提供的解决方案可以很好地工作,当你有一个类的实例,并想知道属性的类型。但是,如果要在没有实例的情况下检查类的属性,您可能会对我的解决方案感兴趣。

I have a solution that finds the name and type of a property given any class that inherits from NSObject.

我有一个解决方案,找到任何继承自NSObject的类的属性的名称和类型。

I wrote a lengthy explanation on * here, and my project is available here on Github,

我在这里写了一篇关于*的冗长解释,我的项目可以在Github上找到,

In short you can do something like this (but really check out the code 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
}