遵循协议的类扩展中如何避免重写get/set并使用默认实现
问题解决:协议扩展中属性默认实现的无限递归问题
错误原因
你写的计算属性会触发无限递归:
get方法里返回self.didSelectSpecificCoinClousre,会再次调用该属性的get方法,循环往复set方法里给self.didSelectSpecificCoinClousre赋值,又会触发set方法,形成死循环
所以编译器抛出了“Function call causes an infinite recursion”警告。
解决方案
Swift协议扩展无法直接添加存储属性,要实现{ get set }属性的默认实现,有两种可行方式:
方式1:用关联对象实现(适用于继承NSObject的类)
借助Objective-C运行时的关联对象,给协议扩展模拟存储属性:
首先修改协议,添加@objc标记并继承NSObjectProtocol:
@objc protocol SelectedSpecificCoinProtocol: NSObjectProtocol { typealias didSelectHandler = () -> Void? var didSelectSpecificCoinClousre: didSelectHandler? { get set } }
然后在协议扩展中实现属性的get/set:
// 定义唯一关联键 private var didSelectKey = 0 extension SelectedSpecificCoinProtocol where Self: NSObject { var didSelectSpecificCoinClousre: didSelectHandler? { get { return objc_getAssociatedObject(self, &didSelectKey) as? didSelectHandler } set { objc_setAssociatedObject(self, &didSelectKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } }
这样,只要你的类继承NSObject并遵循该协议,就自动获得属性的默认实现,无需手动重写。
方式2:让遵循协议的类自行定义存储属性
如果不想依赖Objective-C运行时,最简单的方式是让每个遵循协议的类直接定义存储属性:
protocol SelectedSpecificCoinProtocol { typealias didSelectHandler = () -> Void? var didSelectSpecificCoinClousre: didSelectHandler? { get set } } // 示例类 class CoinSelector: SelectedSpecificCoinProtocol { // 直接定义存储属性,自动满足协议要求 var didSelectSpecificCoinClousre: didSelectHandler? }
这种方式无需额外代码,只是每个遵循协议的类都要自己声明这个属性。
小提示
你的类型别名() -> (Void)?可以简化为() -> Void?,语法更简洁,功能完全一致。
内容的提问来源于stack exchange,提问作者Hello422
相关产品推荐
相关产品推荐

