Why does the `schedTimer` plugin work properly when configured outside the block, but not inside the block?

The following code snippet works fine when called outside the completion block, but the timer never starts when I set it inside the block. I do not understand why there is a difference:

self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.foo), userInfo: nil, repeats: true) 

I did not use my own links when calling initially outside the block, but then once inside, this was required. However, I checked the same code again outside the block, and it still works.

This block is the termination handler that is called after the permission request for the associated HealthKit information.

+15
ios swift swift3
source share
3 answers

The problem is that the completion block in question was probably not executed in the main thread and therefore did not have a run loop. But timers should be scheduled in the run loop, and although the main thread has one, most background threads don't (unless you add one yourself).

To fix this, in this completion handler, send the timer creation back to the main thread, and it should work fine:

 DispatchQueue.main.async { self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(handleTimer(_:)), userInfo: nil, repeats: true) } 

Or use a dispatch source timer (a timer that can be scheduled for a background queue and does not require a run loop).

 var timer: DispatchSourceTimer! private func startTimer() { let queue = DispatchQueue(label: "com.domain.app.timer") timer = DispatchSource.makeTimerSource(queue: queue) timer.setEventHandler { [weak self] in // do something } timer.schedule(deadline: .now(), repeating: 1.0) timer.resume() } 

The syntax for an earlier version of Swift is in a previous version of this answer .

+45
source share

Another reason Timer () may not work is how it is created. I had the same problem, and everything I tried did not solve it, including creating instances in the main thread. I looked at it for a long time until I realized (stupidly) that I was creating it differently. Instead of Timer.scheduledTimer

I created it using

 let timer = Timer(timeInterval: 4.0, target: self, selector: #selector(self.timerCompletion), userInfo: nil, repeats: true) 

In my case, I had to add it to the run loop to start it. Like this

 RunLoop.main.add(timer, forMode: RunLoop.Mode.default) 
+2
source share

This may seem obvious, but I had a similar problem, the timer simply did not work, and the reason was that it was not in the main thread ... No errors, it just never worked.

Put in the main thread, and at least you have a chance!

  DispatchQueue.main.async { //insert your timer here } 
0
source share

All Articles