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

项目地址

GitHub

加我微信沟通。


上一篇 下一篇

猜你喜欢

热点阅读