使用反射在纯Swift中使用它的字符串名称获取属性的值

Chr*_*nce 6 reflection swift

我想使用Swift(不是Objective-C运行时)Reflection来创建这样的方法:

func valueFor(property:String, of object:Any) -> Any? {
    ...
}
Run Code Online (Sandbox Code Playgroud)

在某种程度上,我可以这样做:

func valueFor(property:String, of object:Any) -> Any? {
    let mirror = Mirror(reflecting: object)
    return mirror.descendant(property)
}
Run Code Online (Sandbox Code Playgroud)

class TestMe {
    var x:Int!
}

let t = TestMe()
t.x = 100
let result = valueFor(property: "x", of: t)
print("\(result); \(result!)")
Run Code Online (Sandbox Code Playgroud)

这打印出我期望的东西:

可选(100); 100

当我做:

let t2 = TestMe()    
let result2 = valueFor(property: "x", of: t2)
print("\(result2)")
Run Code Online (Sandbox Code Playgroud)

输出是:

可选(无)

这似乎是合理的,除非我这样做:

var x:Int!
print("\(x)")
Run Code Online (Sandbox Code Playgroud)

打印出:

而不是Optional(nil).底线是我有困难编程确定的值t2.xnil使用我的valueFor方法.

如果我继续上面的代码:

if result2 == Optional(nil)! {
    print("Was nil1")
}

if result2 == nil {
    print("Was nil2")
}
Run Code Online (Sandbox Code Playgroud)

这些print陈述都没有输出任何内容.

当我将断点放入Xcode并查看result2调试器的值时,它显示:

? Optional<Any>
  - some : nil
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是:如何使用结果确定原始成员变量是否为零valueFor

附加1: 如果我这样做:

switch result2 {
case .some(let x):
    // HERE
    break
default:
    break
}
Run Code Online (Sandbox Code Playgroud)

并且在断点处HERE,x的值结果是nil.但是,即使我Any?把它分配给一个,比较它nil也不是真的.

附加2: 如果我这样做:

switch result2 {
case .some(let x):
    let z:Any? = x
    print("\(z)")
    if z == nil {
        print("Was nil3")
    }
    break
default:
    break
}
Run Code Online (Sandbox Code Playgroud)

这打印出来(仅):

可选(无)

我发现这特别奇怪.result2打印出完全相同的东西!

Chr*_*nce 2

这有点像黑客,但我认为这会解决我的问题。我仍在寻找更好的解决方案:

func isNilDescendant(_ any: Any?) -> Bool {
    return String(describing: any) == "Optional(nil)"
}

func valueFor(property:String, of object:Any) -> Any? {
    let mirror = Mirror(reflecting: object)
    if let child = mirror.descendant(property), !isNilDescendant(child) {
        return child
    }
    else {
        return nil
    }
}
Run Code Online (Sandbox Code Playgroud)