Jess Jess - 19 days ago 11
Swift Question

How can I invalidate/deinit a NSTimer without doing it in viewWillDisappear?

var faderTimer: NSTimer?
override func viewDidLoad() {
super.viewDidLoad()

self.faderTimer = NSTimer.scheduledTimerWithTimeInterval(self.fadeTime, target: self, selector: Selector("fadeBackground"), userInfo: nil, repeats: true)
}


I need to invalidate this timer before the controller deinits.

deinit {
//never gets called
if let timer = self.faderTimer {
self.faderTimer!.invalidate()
self.faderTimer = nil
}
}


However, I can't stick it in the deinit(). It seems that I have to invalidate it in
viewWillDisappear
. However, I don't want to do that, because it messes up the background switching. (Returning from background doesn't call viewWillAppear, so I have to use notifications to start the timer, which is a huge pain.) I rather just start the timer on viewDidLoad and stop it on deinit().

Answer

I rather just start the timer on viewDidLoad and stop it on deinit()

Well, you can't. The timer is retaining you (self), and will continue to do so until it is invalidated. This means that unless you take action to invalidate the timer elsewhere, deinit will never be called and the view controller will leak (it will never go out of existence, and all the memory it is holding, along with that of all its properties, will continue to be held). You must find another place to invalidate the timer; that's just the way it is.

If you don't like that, then don't use NSTimer. Use GCD and dispatch_source_t instead. This has the advantage that it is based around a block (a closure) - and you can use weak self or unowned self inside the block to prevent yourself from being retained, and thus you can invalidate the timer in deinit if you want to. That is exactly why I have created a GCD-based timer class, as a substitute for NSTimer.