Swift: отражение переменных протокола

У меня есть протокол с некоторыми переменными { 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 в детей Mirror?

извините за дерьмовый пример, это всего лишь быстрый пример:)

1 ответ

Решение

Вычисленные свойства не представлены в самоанализе времени выполнения, предоставленном Mirror

Из справочника по языку - Зеркальная структура (выделено мной)

Представление подструктуры и необязательного "стиля отображения" любого произвольного субъектного экземпляра.

Описывает части - такие как хранимые свойства, элементы коллекции, элементы кортежа или регистр активного перечисления -которые составляют конкретный экземпляр. Может также предоставлять свойство "стиль отображения", которое предлагает, как эта структура может быть отображена.

Свойства id (int) а также isItTrue (bool) доступны для экземпляров MirrorMe, но только как вычисленные свойства, как MirrorMe не реализует их как хранимые свойства, а использует их реализацию по умолчанию как вычисленные свойства из extension SomeProtocol where Self: SomeClass { ... }, Следовательно, вычисленные свойства id а также isItTrue из MirrorMe не содержатся в представлении подструктуры 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).

Другие вопросы по тегам