使用反射

时间:2017-05-04 23:25:10

标签: swift reflection

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

func valueFor(property:String, of object:Any) -> Any? {
    ...
}

在某种程度上,我可以使用以下方式执行此操作:

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

使用

class TestMe {
    var x:Int!
}

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

这打印出我期望的内容:

  

可选(100); 100

当我这样做时:

let t2 = TestMe()    
let result2 = valueFor(property: "x", of: t2)
print("\(result2)")

输出结果为:

  

可选(无)

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

var x:Int!
print("\(x)")

打印出来:

  

而不是Optional(nil)。最重要的是,我无法使用我的t2.x方法以编程方式确定nil的值为valueFor

如果我继续上述代码:

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

if result2 == nil {
    print("Was nil2")
}

这些print语句都没有输出任何内容。

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

▿ Optional<Any>
  - some : nil

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

Additional1: 如果我这样做:

switch result2 {
case .some(let x):
    // HERE
    break
default:
    break
}

并在HERE处设置断点,x的值变为nil。但是,即使我将其分配给Any?,将其与nil进行比较也不是真的。

Additional2: 如果我这样做:

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

打印出(仅):

  

可选(无)

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

2 个答案:

答案 0 :(得分: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
    }
}

答案 1 :(得分:0)

好吧,我知道已经 4 年了,但我使用的是 Xcode 12 并且仍然面临同样的问题。由于这个问题似乎没有答案,我将添加对我有用的内容。

func valueFor(property: String, of object: Any) -> Any? {
    let optionalPropertyName = "some"
    let mirror = Mirror(reflecting: object)
    if let child = mirror.descendant(property) {
        if let optionalMirror = Mirror(reflecting: child), optionalMirror.displayStyle == DisplayStyle.optional {
            return optionalMirror.descendant(optionalPropertyName)
        } else {
            return child
        }
    } else {
        return nil
    }
}

通过使用 Mirror 检查可选项,然后使用“some”提取可选项,您将返回一个真正的对象或 nil。当它通过 Any? 返回给调用者时?返回,您现在可以检查该值并使其正常工作。