【问题标题】:Swift: reflection of protocol variablesSwift:协议变量的反射
【发布时间】:2023-03-16 18:26:01
【问题描述】:

我有一个协议,其中包含一些 { 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 仅返回我在子类中设置的协议变量。如何在 Mirror 的孩子中同时包含 idisItTrue

附言对不起这个糟糕的例子,这只是一个简单的例子:)

【问题讨论】:

  • 老兄,你用的是什么版本的 XCode? :)我的问题有一些部分答案:当我在子类初始化后中断时,我在调试器中看不到协议变量,我可以通过 po something 打印它们,但在 XCode 的变量树中看不到它们

标签: swift mirroring


【解决方案1】:

Mirror 提供的运行时自省中没有表示计算属性

来自the Language Reference - Mirror struct(重点由我添加)

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

描述部分——例如存储的属性、集合元素、 元组元素,或活动枚举案例---组成一个 具体实例。也可以提供一个“显示样式”属性, 建议如何呈现这种结构。

属性id (int) 和isItTrue (bool) 可用于MirrorMe 的实例,但只能作为计算属性,因为MirrorMe 不能将它们实现为存储属性,而是将它们的默认实现用作来自extension SomeProtocol where Self: SomeClass { ... } 的计算属性。因此,MirrorMe 的计算属性 idisItTrue 不包含在 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 */

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

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

【讨论】:

  • var id: Int { get set } 是因为对代码进行了多次编辑。我纠正了它。并感谢您的回答。我认为在扩展中分配的值会产生影响,但无论如何:) 我将手动将计算的属性添加到字典中。谢谢大家!
  • @user3352185 乐于助人!请务必记下我回答中的最后一段(谨防运行时自省黑客!)
猜你喜欢
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-15
相关资源
最近更新 更多