Reputation: 4984
I am using Timer
instance in my project.
I create and add an instance to RunLoop
timer = Timer(timeInterval: 0.1, repeats: true, block: { (timer) in
print("Hello")
})
if let timer = timer {
RunLoop.current.add(timer, forMode: .commonModes)
}
Now I am thinking about how to properly stop and remove Timer:
Maybe deinit
implementation is need. If is it true, what should be inside
deinit {
longPressTimer?.invalidate()
longPressTimer = nil
}
invalidate
is nesseccery? = nil
?
I have read serval threads from Stack about it but answers are contradictory. Could someone tell me which way is properly and explain me why?
Upvotes: 0
Views: 3505
Reputation: 2149
First check whether timer exist? if yes then invalidate it like
if timer!= nil {
timer.invalidate()
}
Keep in mind that if you use a timer in any VC invalidate it when you leave that VC(View Controller)
Upvotes: 0
Reputation: 804
You need both invalidate() and = nil. Unlike other objects, a timer DOES NOT get deallocated when its retain count reaches zero unless it's stopped (invalidated).
Say, if you have a repeating timer which is currently active. when you set timer = nil, it still persists in memory and keeps triggering the action (probably the iOS has some kinds of mechanism to keep it alive as long as it's still active). So the rule of thumb is: Always call invalidate() and set the timer to nil when you want to get rid of it.
Upvotes: 2
Reputation: 19792
If timer is repeating it won't invalidate as long as it's target is in memory.
The best solution for me was to use this class - which will observe target, and it target is deallocate it will invalidate itself.
final class WeakTimer {
private weak var timer: Timer?
private weak var target: AnyObject?
private let action: (Timer) -> Void
private init(timeInterval: TimeInterval,
target: AnyObject,
repeats: Bool,
userInfo: Any?,
action: @escaping (Timer) -> Void) {
self.target = target
self.action = action
self.timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector: #selector(fire(timer:)), userInfo: userInfo, repeats: repeats)
RunLoop.main.add(self.timer!, forMode: .commonModes)
}
class func scheduledTimer(timeInterval: TimeInterval,
target: AnyObject,
userInfo: Any?,
repeats: Bool,
action: @escaping (Timer) -> Void) -> Timer {
return WeakTimer(timeInterval: timeInterval,
target: target,
repeats: repeats,
userInfo: userInfo,
action: action).timer!
}
@objc fileprivate func fire(timer: Timer) {
if target != nil {
action(timer)
} else {
timer.invalidate()
}
}
}
Upvotes: 1