Ogre Codes

Follow @ogre_codes to get notified when new articles are posted to this site.

👨🏻‍💻

Dealing with Timers in a View Controller 👨🏻‍💻

Feb 19, 2017, 12:08 AM

My instant preview uses a timer that checks if the page has updated and if it has, updates the webview. To do this, I set up a timer with a callback to a class method on the View Controller.

If you want to use a timer in a View Controller in iOS, it's fairly simple, just add the timer in viewWillAppear.

timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(timedServices), userInfo: nil, repeats: true);

What is less obvious is the fact that timers persist beyond the life of the view and keep polling the selected method long after you've exited the page where you launched them from. This creates a memory retention cycle, the timer is hanging onto a reference to the View Controller so it can access it's method and the View Controller is hanging onto a reference to the timer. Additionally, it's burning CPU time (and by extension battery life) checking to see if it needs to update a view which is no longer valid.

The solution I came up with was to check if the view was visible in the timer event and if it wasn't, invalidate the timer. It turns out this was somewhat overengineered; there is a much simpler way to do this simply by invalidating the timer in viewWillDisappear.

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    timer?.invalidate()
}

Source StackOverflow.

By having the timer start and stop in viewWillAppear and viewWillDisappear respectively, you ensure it's running the entire time the view is active and no longer. In more general terms, this is a good way to keep the program balanced. If you set something up in viewWillAppear, there's a fair chance you'll need to set up some kind of teardown code in viewWillDisappear, keeping things balanced makes housekeeping a lot simpler.

.