Swift:协议(protocol)变量的反射

标签 swift mirroring

我有一个带有一些 { get } 和 { get set } 变量和扩展的协议(protocol),我在其中设置了前者,并在初始化类时也设置了后者。我想在字典中返回所有这些,即:

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 仅返回我在子类中设置的协议(protocol)变量。我如何在 Mirror 的 child 中同时包含 idisItTrue

附注抱歉这个蹩脚的例子,这只是一个简单的例子:)

最佳答案

计算属性未在 Mirror 提供的运行时内省(introspection)中表示

来自 the Language Reference - Mirror struct (重点是我加的)

Representation of the sub-structure and optional "display style" of any arbitrary subject instance.

Describes the parts---such as stored properties, collection elements, tuple elements, or the active enumeration case---that make up a particular instance. May also supply a "display style" property that suggests how this structure might be rendered.

属性 id (int) 和 isItTrue (bool) 可用于 的实例MirrorMe,但仅作为计算属性,因为MirrorMe 不将这些实现为存储属性,而是将它们的默认实现用作计算属性来自 extension SomeProtocol where Self: SomeClass { ... }。因此,MirrorMe 的计算属性 idisItTrue 不包含在 MirrorMe 实例的子结构表示中,由使用 Mirror 的运行时内省(introspection)提供。

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

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 */

总而言之:协议(protocol)中的蓝图属性,无论是否有关联的默认实现,都永远不能单独存储属性(蓝图属性的默认实现自然可能只包含计算属性)。这意味着在对此类类/结构的实例应用运行时内省(introspection)时,只有符合您的协议(protocol)的类/结构中明确声明为存储属性的属性才会显示。

最后,您从未提及您想要一个类实例的存储属性字典的原因,但如果将其用于生产目的,请小心。通常,使用 Swift 等类型安全语言的运行时自省(introspection)应该只用于诊断和调试,即使它允许在运行时 hack 中使用(例如,对于从 NSObject 继承的类使用 KVO)。

关于Swift:协议(protocol)变量的反射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45242907/

相关文章:

swift - 如果主队列始终同步,为什么 dispatchQueue.main 会给我同步或异步选项

ios - 如何检查 UIPageViewController VC 何时更改为另一个?

algorithm - 确定镜像延迟(镜像是使用 rsync 和 rsh 完成的)

php - 确定最近的镜像 PHP

git - 始终保持 git 镜像同步

ios - 在 BarButtonItem Swift 上添加角标(Badge)计数图标

ios - 在 xcode 中处理多个数据输入菜单的最方便的方法

类不符合 swift 协议(protocol)

iphone - Linux Mint 19 - 镜像 iPhone

file - 即时将文件从Windows镜像/同步到Linux服务器的最佳方法