获取Swift变量的实际名称作为字符串

时间:2014-09-23 22:24:21

标签: swift reflection

所以我试图在Swift中将实际变量名称作为字符串,但是还没有找到方法这样做......或者我可能正在以一个不好的角度看待这个问题和解决方案。

所以这基本上就是我想做的事情:

var appId: String? = nil

//This is true, since appId is actually the name of the var appId
if( appId.getVarName = "appId"){
    appId = "CommandoFurball"
}

不幸的是,我无法在苹果文档中找到任何与此相近的内容,但是:

varobj.self or reflect(var).summary 

然而,这给出了变量本身内部或变量类型的信息,在这种情况下是String,我想要变量的实际名称。

6 个答案:

答案 0 :(得分:48)

使用#keyPath()

Swift 3 中正式支持此功能

https://github.com/apple/swift-evolution/blob/master/proposals/0062-objc-keypaths.md

示例用法如下:

NSPredicate(format: "%K == %@", #keyPath(Person.firstName), "Wendy")

Swift 4 中我们有更好的表现:\KeyPath符号

https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md

NSPredicate(format: "%K == %@", \Person.mother.firstName, "Wendy")

// or

let keyPath = \Person.mother.firstName
NSPredicate(format: "%K == %@", keyPath, "Andrew")

速记是一个受欢迎的补充,能够从变量引用键路径是非常强大的

答案 1 :(得分:25)

根据this answer的更新,通过#keyPath

支持Swift 3
NSPredicate(format: "%K == %@", #keyPath(Person.firstName), "Andrew")

答案 2 :(得分:3)

这是我的解决方法

class Test { 
    var name: String = "Ido"
    var lastName: String = "Cohen"
}

let t = Test()
let mirror = Mirror(reflecting: t)

for child in mirror.children {
    print(child.label ?? "")
}

将是

name
lastName

答案 3 :(得分:1)

最佳解决方案是Here

来自指定链接

import Foundation

extension NSObject {
//
// Retrieves an array of property names found on the current object
// using Objective-C runtime functions for introspection:
// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html
//
func propertyNames() -> Array<String> {
    var results: Array<String> = [];

    // retrieve the properties via the class_copyPropertyList function
    var count: UInt32 = 0;
    var myClass: AnyClass = self.classForCoder;
    var properties = class_copyPropertyList(myClass, &count);

    // iterate each objc_property_t struct
    for var i: UInt32 = 0; i < count; i++ {
        var property = properties[Int(i)];

        // retrieve the property name by calling property_getName function
        var cname = property_getName(property);

        // covert the c string into a Swift string
        var name = String.fromCString(cname);
        results.append(name!);
    }

    // release objc_property_t structs
    free(properties);

    return results;
}

}

答案 4 :(得分:1)

我已经提出了一个快捷的解决方案,但不幸的是它不适用于Int的Float's和Double's 我相信。

func propertyNameFor(inout item : AnyObject) -> String{
    let listMemAdd = unsafeAddressOf(item)
    let propertyName =  Mirror(reflecting: self).children.filter { (child: (label: String?, value: Any)) -> Bool in
        if let value = child.value as? AnyObject {
            return listMemAdd == unsafeAddressOf(value)
        }
        return false
        }.flatMap {
            return $0.label!
    }.first ?? ""

    return propertyName
}

var mutableObject : AnyObject = object
let propertyName = MyClass().propertyNameFor(&mutableObject)

它比较对象属性的内存地址,并查看是否有匹配。 它不适用于Int's Float和Double的原因,因为它们不属于任何对象类型,尽管你可以将它们作为任何对象传递,当你这样做时转换为NSNumbers。因此内存地址会发生变化。 they talk about it here.

对于我的应用程序,它根本不会阻碍我,因为我只需要它来进行自定义类。所以也许有人会觉得这很有用。如果任何人都可以使用其他数据类型工作,那将非常酷。

答案 5 :(得分:1)

这有效:

struct s {
    var x:Int = 1
    var y:Int = 2
    var z:Int = 3
}

var xyz = s()

let m = Mirror(reflecting: xyz)

print(m.description)
print(m.children.count)
for p in m.children {
    print(p.label as Any)
}