Search code examples
swifttimerclosures

Why does timer continue to execute after invalidation?


If you run the code below, even after I invalidate the timer, the remaining code of the timer executes without any disruption. Why?

Is it because the closure has a strong reference to itself and is retained until it completely finishes itself? Or something else?

Does this mean invalidating a timer during its moment of execution does nothing?

class ViewController: UIViewController {

    var timer : Timer?
    let serialQueue = DispatchQueue(label: "com.createTimer.serial")

    override func viewDidLoad() {
        super.viewDidLoad()

        serialQueue.sync { [weak self] in
            self?.timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: false, block: { [weak self] _ in
                self?.someDummyFunc()
                print("yyy")
                print("\(self?.timer?.isValid)")
            })
        }
    }

    func someDummyFunc(){
        print("\(timer?.isValid)")
        print("xxx")
        timer?.invalidate()
    }
}

The prints that I get from running this code is:

Optional(true)
xxx
yyy
Optional(false) // timer.isValid is false !!!

Yet what I initially thought I would get is:

Optional(true)
xxx

Solution

  • The scheduledTimer(withTimeInterval:repeats:block:) method:

    After interval seconds have elapsed, the timer fires, executing block.

    The invalidate() method:

    Stops the timer from ever firing again

    You are correct in your discovery that invalidating a timer will not interrupt a currently executing block, but will only prevent future executions of that block.