Reference counting (ARC) in iOS is awesome: It is fast, predictable, and uses less RAM. Sometimes it can be a challenge to work with, though. Timers are one of those things.
It is really easy to accidentally create a circular reference with timers in iOS. A circular reference is where A references B, B references C, and C references A. None of those objects can be released, because their reference counts can never reach zero. This is a cause of app instability, and if you understand how to avoid this, you’ll be a better developer.
Timers in particular can trip you up here, because there’s a lot of references to be aware of:
One more thing to beware:
So here’s Pendulum and Countdown, my solution to all these issues:
/// This is a wrapper around a repeating Timer.
/// You don't need to worry about invalidating it, just set it
/// to nil and that's taken care of for you.
/// This can be handy for if you want to use this eg in a state
/// machine enum: Simply change the state and the timer vanishes.
/// Be careful that your closure doesn't strongly reference self,
/// or you may cause a retain loop, such as:
/// MyViewController -> Pendulum -> closure -> MyViewController.
class Pendulum {
let timer: Timer
init(seconds: TimeInterval, closure: @escaping () -> ()) {
timer = Timer.scheduledTimer(withTimeInterval: seconds,
repeats: true, block: { _ in
closure();
})
}
deinit {
timer.invalidate()
}
}
/// This is like Pendulum, but does not repeat.
class Countdown {
let timer: Timer
init(seconds: TimeInterval, closure: @escaping () -> ()) {
timer = Timer.scheduledTimer(withTimeInterval: seconds,
repeats: false, block: { _ in
closure();
})
}
deinit {
timer.invalidate()
}
}
And here’s how to use it:
class MyViewController: UIViewController {
var pendulum: Pendulum?
override func viewDidLoad() {
super.viewDidLoad()
pendulum = Pendulum(seconds: 1, closure: {
[weak self] in
self?.doSomethingEverySecond()
})
}
func doSomethingEverySecond() {
// ...
}
}
Thanks for reading, and have a great week!
Photo by Jon Tyson on Unsplash
Thanks for reading! And if you want to get in touch, I'd love to hear from you: chris.hulbert at gmail.
(Comp Sci, Hons - UTS)
Software Developer (Freelancer / Contractor) in Australia.
I have worked at places such as Google, Cochlear, Assembly Payments, News Corp, Fox Sports, NineMSN, FetchTV, Coles, Woolworths, Trust Bank, and Westpac, among others. If you're looking for help developing an iOS app, drop me a line!
Get in touch:
[email protected]
github.com/chrishulbert
linkedin