I was trying to add a timer property in an extension. The code is as follow
@objc public extension RCTTouchHandler {
static let kSessionTimer = "sessionTimer"
var sessionTimer: Timer {
get {
return objc_getAssociatedObject(self, RCTTouchHandler.kSessionTimer) as? Timer ?? Timer.scheduledTimer(timeInterval: RCTTouchHandler.kSessionExpiredDuration, target: self, selector: #selector(touchSessionExpiration), userInfo: nil, repeats: false)
}
set(timer) {
objc_setAssociatedObject(self, RCTTouchHandler.kSessionTimer, self, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
@objc func touchSessionExpiration() {
print("session expired")
}
deinit {
self.sessionTimer.invalidate()
}
}
Then,sessionTimer
has strong reference to this object, in the meantime, this object strongly retains sessionTimer
. To avoid retain-cycle and memory leak, I should invalid the timer when the object is deinitialized. But, I encountered the following error when trying to invalidate the timer in the deinit func in this extension.
Deinitializers may only be declared within a class
According to Swift Doc
Extensions can add new convenience initializers to a class, but they cannot add new designated initializers or deinitializers to a class. Designated initializers and deinitializers must always be provided by the original class implementation.
So I am wondering how should I invalidate the timer properly in this extension?
As you stated, you cannot implement deinit { }
in extensions.
You could create your own object and implement deinit { }
there and instead of using RCTTouchHandler
everywhere, use your own object:
@objc extension RCTTouchHandler {
static let kSessionTimer = "sessionTimer"
}
public class MyTouchHandler: RCTTouchHandler {
private var timer: Timer? = nil
var sessionTimer: Timer {
get {
guard let timer = timer else {
let newTimer = Timer.scheduledTimer(timeInterval: RCTTouchHandler.kSessionExpiredDuration, target: self, selector: #selector(touchSessionExpiration), userInfo: nil, repeats: false)
self.timer = newTimer
return newTimer
}
return timer
}
set(timer) {
self.timer = timer
}
}
@objc func touchSessionExpiration() {
print("session expired")
}
deinit {
self.timer?.invalidate()
}
}