Swift 版本的对象临终遗言
2018-11-17 本文已影响3人
BudSwift
如果需要在某个对象释放时执行特定的任务,比如移除通知、观察者的监听。除了手动在 deinit 中处理外,可以使用运行时的 objc_assocatio 和 closure 对这一需求进行封装。
封装 closure 执行对象
将 deinit 时需要执行的 closure 封装为一个对象,此对象将在 deinit 时调用 closure
enum XDeinit { // 嵌套类型
class BlockExecutor {
var block: (()->Void)?
init(_ block: (()->Void)?) { self.block = block }
deinit {
if let block = block { block() }
}
}
}
通过 extension 提供遗言功能
提供给 NSObject 子类可以留下最终消息的操作方法,并在内部进行对象组装,以及属性关联
extension NSObject {
static var LastWordsKey: Any? = nil // 类属性作为 key 值使用
func leave(with lastWords: (()->Void)?) {
let ex = XDeinit.BlockExecutor(lastWords)
objc_setAssociatedObject(self, &NSObject.LastWordsKey, ex, .OBJC_ASSOCIATION_RETAIN)
}
}
如此以来,包装的 BlockExcutor B 被对象 A 强引用,当 A 释放时,B 随之也释放,进而调用了 B 的 deinit 中的 closure。
可以使用如下代码在 SwiftPlayground 中进行测试。
var obj: NSObject? = nil
obj = NSObject()
obj?.leave { print("be good.") }
obj = nil
项目地址
加我微信沟通。