在 Swift 中(我使用的是 4.1),有没有办法在对象被破坏时在扩展中进行一些清理?我想到了deinit()
的代码类型,但扩展不能声明deinit()
。(除此之外,如果需要多个扩展来执行此操作,则会有多个deinit()
声明。
我没有找到一种方法来准确获得您想要的东西,但也许这段代码会有所帮助。我从未尝试过,所以也许更多地使用它作为灵感。简而言之,它允许您添加将在取消初始化时执行的代码位。
/// This is a simple object whose job is to execute
/// some closure when it deinitializes
class DeinitializationObserver {
let execute: () -> ()
init(execute: @escaping () -> ()) {
self.execute = execute
}
deinit {
execute()
}
}
/// We're using objc associated objects to have this `DeinitializationObserver`
/// stored inside the protocol extension
private struct AssociatedKeys {
static var DeinitializationObserver = "DeinitializationObserver"
}
/// Protocol for any object that implements this logic
protocol ObservableDeinitialization: AnyObject {
func onDeinit(_ execute: @escaping () -> ())
}
extension ObservableDeinitialization {
/// This stores the `DeinitializationObserver`. It's fileprivate so you
/// cannot interfere with this outside. Also we're using a strong retain
/// which will ensure that the `DeinitializationObserver` is deinitialized
/// at the same time as your object.
fileprivate var deinitializationObserver: DeinitializationObserver {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.DeinitializationObserver) as! DeinitializationObserver
}
set {
objc_setAssociatedObject(
self,
&AssociatedKeys.DeinitializationObserver,
newValue,
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
/// This is what you call to add a block that should execute on `deinit`
func onDeinit(_ execute: @escaping () -> ()) {
deinitializationObserver = DeinitializationObserver(execute: execute)
}
}
工作原理
现在让我们假设你有你的对象,我们称之为A
,你想在扩展中创建一些代码,你可以使用onDeinit
添加你的清理代码,如下所示:
extension A {
func someSetup() {
// Do your thing...
onDeinit {
/// This will be executed when A is deinitialized
print("Execute this")
}
}
}
您也可以从扩展程序外部添加它,
let a = A()
a.onDeinit {
print("Deinitialized")
}
讨论
- 这与你想要的有所不同,因为你需要调用一个函数(
deinit
),而不是定义一个函数。但无论如何,在协议扩展中,你永远不能真正使用底层对象的生命周期,所以在大多数情况下应该没问题。 - 我不确定
A
的deinit
和DeinitializationObserver
deinit
之间的执行顺序。在闭包中编写代码时,可能需要放弃A
仍在内存中的假设。 - 如果需要多个
onDeinit
可以更新关联的对象以保留DeinitializationObserver
数组 - 在我的代码中,我通常使用ReactiveCocoa的
Lifetime
来处理这类事情。但是,它比我在这里写的要复杂得多。相反,看起来他们摆动了dealloc
选择器。如果您有兴趣,可以看看里面 - https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/ReactiveCocoa/NSObject+Lifetime.swift