Swift Timer and retain cycles


Greetings, traveler!

Swift Timer is a popular API. Most developers have experience with it. However, this class holds hidden dangers that may take time to be noticeable. I am talking about retaining cycles, which a Timer can cause. Check out this code.

import UIKit

class ViewController: UIViewController {
    
    private var timer: Timer?
    
    override func viewDidLoad() {
        timer = Timer.scheduledTimer(
            timeInterval: 1,
            target: self,
            selector: #selector(action),
            userInfo: nil,
            repeats: true
        )
    }
    
    @objc
    private func action() {
        // do something...
    }
    
}

We have a ViewController that holds a reference to a Timer. The issue is that the object won’t be deallocated after this ViewController is popped or dismissed because its Timer wasn’t invalidated. You can check this by inspecting the memory graph or printing something inside the deinit method.

To solve this issue, we must ensure we have invalidated the Timer. We can do this in different ways. For example, we can call the Timer’s invalidate method inside the ViewControllers viewWillDisappear or viewDidDisappear methods.

Conclusion

While the Swift API provides various automatic memory management tools, we must stay focused constantly.