Swift:协议变量的反映

时间:2016-07-17 17:19:01

标签: swift mirroring

我有一个带有一些{get}和{get set}变量和扩展的协议,我设置了前一个,并在初始化类时 - 设置后者。我想把它们全部归还字典,即:

protocol SomeProtocol {
    var id: Int { get }
    var name: String { get set }
    var isItTrue: Bool { get }
}

extension SomeProtocol where Self: SomeClass {
    var id: Int { return 1 }
    var isItTrue: Bool { return true }

    func classProps() {
        var dict = [String: AnyObject]()
        let mirrorSelf = Mirror(reflecting: self)
        for mirrorChild in mirrorSelf.children { print(mirrorChild.label) }
    }
}

class SomeClass {
// just a class, nothing special
}

class MirrorMe: SomeClass, SomeProtocol {
    var name: String = "Some name"
}

class MirrorMirrorOnTheWall {
    func talkToTheMirror() {
        let mirrorThis = MirrorMe()
        mirrorThis.classProps() // returns only "name" property
    }
}

正如我在评论中写的那样,classProps只返回我在子类中设置的协议变量。如何在镜像的子项中同时包含 id isItTrue

P.S。抱歉这个蹩脚的例子,这只是一个简单的例子:)

1 个答案:

答案 0 :(得分:4)

计算属性未在Mirror

提供的运行时自省中表示

来自the Language Reference - Mirror struct(我强调)

  

子结构的表示和可选的“显示风格”   任意主题实例

     

描述部分---例如存储属性,集合元素,   元组元素,或者组成一个的活动枚举情况---   特定实例。也可能提供“显示风格”属性   建议如何渲染这个结构。

属性idint)和isItTruebool)可用于MirrorMe的实例,但仅作为计算属性< / em>,因为MirrorMe没有将这些实现为存储属性,而是使用它们的默认实现作为extension SomeProtocol where Self: SomeClass { ... }的计算属性。因此,id的计算属性isItTrueMirrorMe不包含在MirrorMe实例的子结构表示中,正如使用Mirror的运行时内省所提供的那样

我们可以在一个更简单的例子中清楚地验证这一点:

class Foo {
    // a stored property
    let representedInIntrospection = 0

    // a computed property
    var notRepresented: Int { return representedInIntrospection }
}

Mirror(reflecting: Foo())
    .children
    .forEach { print($0.label, $0.value) }
        /* Optional("representedInIntrospection") 0 */

总结:协议中蓝色打印的属性(带或不带关联的默认实现)永远不能自己存储属性(blueprinted属性的默认实现自然只能包含计算属性)。这意味着在应用此类/结构的实例的运行时内省时,将显示符合您的协议的类/结构中显式声明为存储属性的唯一属性。

最后,你永远不会提到为什么你想要一个类实例的存储属性的字典的原因,但是如果将这个用作生产目的则要小心。通常,作为Swift的类型安全语言的运行时内省应仅用于诊断和调试,即使它允许在运行时黑客中使用(例如,对于继承自NSObject的类,使用KVO)。