Swift:协议变量的反映
Swift: reflection of protocol variables
我有一个带有一些 { get } 和 { get set } 变量和扩展的协议,我在其中设置了前者,并在初始化 class 时也设置了后者。我想 return 所有这些都在字典中,即:
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
return 只是我在 subclass 中设置的协议变量。我怎样才能在镜子的 children 中同时包含 id 和 isItTrue?
p.s。抱歉这个蹩脚的例子,这只是一个简单的例子:)
计算属性未在 Mirror
提供的运行时内省中表示
来自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
的计算属性 id
和 isItTrue
不包含在 MirrorMe
实例的子结构表示中,正如运行时内省使用 Mirror
提供的那样.
我们可以在一个更小的例子中清楚地验证这一点:
class Foo {
// a stored property
let representedInIntrospection = 0
// a computed property
var notRepresented: Int { return representedInIntrospection }
}
Mirror(reflecting: Foo())
.children
.forEach { print([=10=].label, [=10=].value) }
/* Optional("representedInIntrospection") 0 */
总而言之:协议中的蓝图属性,无论是否有关联的默认实现,都永远不能单独存储属性(蓝图属性的默认实现自然可能只包含计算属性)。这意味着只有 在 class/struct 中明确声明为存储属性 且符合您的协议的属性将在应用此类 [= 实例的运行时内省时显示43=].
最后,你从来没有提到为什么你想要一个 class 实例的存储属性的字典,但是如果将它用于生产目的,请小心。通常,使用 Swift 类型安全语言的运行时自省应该只用于诊断和调试,即使它允许在运行时 hack 中使用(例如,对于 classes 继承自 [=24 的 KVO =]).
我有一个带有一些 { get } 和 { get set } 变量和扩展的协议,我在其中设置了前者,并在初始化 class 时也设置了后者。我想 return 所有这些都在字典中,即:
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
return 只是我在 subclass 中设置的协议变量。我怎样才能在镜子的 children 中同时包含 id 和 isItTrue?
p.s。抱歉这个蹩脚的例子,这只是一个简单的例子:)
计算属性未在 Mirror
提供的运行时内省中表示
来自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
的计算属性 id
和 isItTrue
不包含在 MirrorMe
实例的子结构表示中,正如运行时内省使用 Mirror
提供的那样.
我们可以在一个更小的例子中清楚地验证这一点:
class Foo {
// a stored property
let representedInIntrospection = 0
// a computed property
var notRepresented: Int { return representedInIntrospection }
}
Mirror(reflecting: Foo())
.children
.forEach { print([=10=].label, [=10=].value) }
/* Optional("representedInIntrospection") 0 */
总而言之:协议中的蓝图属性,无论是否有关联的默认实现,都永远不能单独存储属性(蓝图属性的默认实现自然可能只包含计算属性)。这意味着只有 在 class/struct 中明确声明为存储属性 且符合您的协议的属性将在应用此类 [= 实例的运行时内省时显示43=].
最后,你从来没有提到为什么你想要一个 class 实例的存储属性的字典,但是如果将它用于生产目的,请小心。通常,使用 Swift 类型安全语言的运行时自省应该只用于诊断和调试,即使它允许在运行时 hack 中使用(例如,对于 classes 继承自 [=24 的 KVO =]).