Swift 扩展「可以」添加存储属性
好吧,其实我标题党了:Swift 扩展只能添加计算属性。然而如果你愿意用 Objective-C 的关联对象,你可以在 Swift 中做一些同样有趣的事。有很多的模板可供选择,然而如果你用这些太过显然的方式,你也就牺牲了类型安全。我们可以做得更好吗? 当然可以。这里就是一些这样的函数,使用 Swift 类型推断的黑魔法,使你在类或协议扩展中写类型安全的非 Optional 计算属性时,就像存储属性一样。 import Foundation func associatedObject<ValueType: AnyObject>( base: AnyObject,key: UnsafePointer<UInt8>,initialiser: () -> ValueType) -> ValueType { if let associated = objc_getAssociatedObject(base,key) as? ValueType { return associated } let associated = initialiser() objc_setAssociatedObject(base,key,associated,.OBJC_ASSOCIATION_RETAIN) return associated } func associateObject<ValueType: AnyObject>( base: AnyObject,value: ValueType) { objc_setAssociatedObject(base,value,.OBJC_ASSOCIATION_RETAIN) } 函数就那么长。你可以这样使用它们: class Miller {} // 这是我们要扩展的类 class Cat { // 每个磨坊主都有一只猫 var name = “Puss” } private var catKey: UInt8 = 0 // 我们还是需要这样的模板 extension Miller { var cat: Cat { // cat「实际上」是一个存储属性 get { return associatedObject(self,key: &catKey) { return Cat() } // 设置变量的初始值 } set { associateObject(self,key: &catKey,value: newValue) } } } 如果你在家可以跟着练习的话,你可以在 playground 中敲下下面几行代码,来确保它能正常工作。 let grumpy = Miller() grumpy.cat.name // 显示 Puss grumpy.cat.name = “Hephaestos” grumpy.cat.name // 显示 Hephaestos 就这么简单! 致谢:这个实现至少一半来自于 Eric-Paul Lecluse。他在扩展中使用了关联对象,我把这个模式提出来作为一个可重用的类,然后我们一起把这个类修改成了你看到的那两个方法。代码是我写的,如果其中有任何错误,都是我的锅。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |