如何从 Swift 中的镜像 children 中提取可选类型值?

How to extract optional typed values from Mirror children in Swift?

我有几个 swift class 看起来类似于以下内容

public class Book {
  var title: String?
  var date: NSDate?
}

因为有几个不同的 classes 需要访问属性,我通过 class:

的属性使用对 运行 的反射
let myBook = Book()
myBook.title = "Hello"
myBook.date = NSDate()

let mirror = Mirror(reflecting: myBook)
var propsArr = [(key: String?, value: Any)]()
let mirrorChildrenCollection = AnyRandomAccessCollection(mirror.children)!
if mirrorChildrenCollection.count > 0 {
  propsArr += mirrorChildrenCollection
}

//iterate through properties
for case let (label?, value) in propsArr {
  print (label, value)

  if let val = value as? NSDate {
    var extractedDate = val
    print(extractedDate)
  }
  else if let val = value as? String {
    var extractedTitle = val
    print (extractedTitle)
  }
}

但我有一个问题,即 Child objects 没有被提取,因为它们是 Any 类型并且内部可选 classes,因此不属于我的情况。如果我从 String 更改标题?到字符串,它们确实有效,但我需要使用可选类型。

我可以在上面的实现中更改什么以将数据类型保留为字符串?和日期?并仍然从镜像中提取值?

这似乎在 Swift 2.x 中是不可能的。

由于属性是可选的,因此您必须分别转换为 NSDate?String?,如下所示:

if let val = value as? NSDate? {
    // val is Optional<NSDate>
}

不幸的是,编译器不允许这样做(我不确定为什么):// error: cannot downcast from 'protocol<>' to a more optional type 'NSDate?'.

from bubuxu 提供了一个巧妙的解决方法,如果每个 属性 都有一个 Mirror,那么该方法会起作用。镜像的 displayStyle 属性 告诉你它是不是可选的,然后你可以手动提取包裹的值。所以这会起作用:

let child = Mirror(reflecting: myBook.date)
child.displayStyle
if child.displayStyle == .Optional {
    if child.children.count == 0 {
        // .None
    } else {
        // .Some
        let (_, some) = child.children.first!
        if let val = some as? NSDate {
            print(val)
        }
    }
}

但这取决于每个 属性 都有一个 Mirror,而且您似乎无法遍历 Mirror 的子级来检索 Mirror他们。