如何使用Swift 2.0和反射获取属性名称及其值?

5

给定这个模型:

public class RSS2Feed {

    public var channel: RSS2FeedChannel?

    public init() {}
}

public class RSS2FeedChannel {   

    public var title: String?
    public var description: String?

    public init() {}

}

我需要如何获取 RSS2FeedChannel 实例的属性名和属性值?

这是我尝试的代码:

let feed = RSS2Feed()
feed.channel = RSS2FeedChannel()
feed.channel?.title = "The Channel Title"

let mirror = Mirror(reflecting: feed.channel)
mirror.children.first // ({Some "Some"}, {{Some "The Channel Title...

for (index, value) in mirror.children.enumerate() {
    index // 0
    value.label // "Some"
    value.value // RSS2FeedChannel
}

最终,我正在尝试使用反射创建一个与实例匹配的Dictionary,但是到目前为止,我无法获取实例的属性名称和值。

文档说:

当适当时,可以使用可选标签,例如表示存储属性或活动枚举案例的名称,并将用于在传递给后代方法的字符串时进行查找。

然而,我只得到了一个“Some”字符串。

此外,value属性返回一个带有类型为RSS2FeedChannel的字符串,而我期望每个子元素都是“反射实例结构的一个元素”!

2个回答

5
当我理解正确时,这应该可以解决您的问题:
func aMethod() -> Void {
    let feed = RSS2Feed()
    feed.channel = RSS2FeedChannel()
    feed.channel?.title = "The Channel Title"
//  feed.channel?.description = "the description of your channel"

    guard  let channel = feed.channel else {
        return
    }

    let mirror = Mirror(reflecting: channel)
    for child in mirror.children {
        guard let key = child.label else {
            continue
        }
        let value = child.value

        guard let result = self.unwrap(value) else {
            continue
        }

        print("\(key): \(result)")
    }
}

private func unwrap(subject: Any) -> Any? {
    var value: Any?
    let mirrored = Mirror(reflecting:subject)
    if mirrored.displayStyle != .Optional {
        value = subject
    } else if let firstChild = mirrored.children.first {
        value = firstChild.value
    }
    return value
}

对于Swift 3,只需要进行一些微小的更改:

private func unwrap(_ subject: Any) -> Any? {
    var value: Any?
    let mirrored = Mirror(reflecting:subject)
    if mirrored.displayStyle != .optional {
        value = subject
    } else if let firstChild = mirrored.children.first {
        value = firstChild.value
    }
    return value
}

1
你可以在 Mirror 对象上使用 descendent 方法来获取这些信息。如果未找到值或可选项不包含任何值,则它将返回 nil。
let mirror = Mirror(reflecting: feed.channel)
let child1 = mirror.descendant("Some", "title") // "The Channel Title"

// or on one line
let child3 = Mirror(reflecting: feed).descendant("channel", "Some", "title")

我发现当可选项不包含任何值时,child1的值并不仅仅是nil。请参阅https://dev59.com/a43da4cB1Zd3GeqP3Kow。 - Chris Prince

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接