Why would a `scheduledTimer` fire properly when setup outside a block, but not within a block?

后端 未结 3 1907
醉话见心
醉话见心 2020-12-03 13:29

The following code snippet works perfectly when called outside a completion block, but the timer is never fired when I set it up inside the block. I don\'t understand why th

相关标签:
3条回答
  • 2020-12-03 14:06

    Another reason why Timer() might not work work is how it's created. I had the same problem, and everything I tried didn't solve it, including instantiating on the main thread. I stared at this for quite a while until I realized (stupidly) that I was creating it differently. Instead of Timer.scheduledTimer

    I instantiated it using

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

    In my case I had to actually add it to a run loop to get it to run. Like this

    RunLoop.main.add(timer, forMode: RunLoop.Mode.default)
    
    0 讨论(0)
  • 2020-12-03 14:11

    The issue is that the completion block in question was probably not running on the main thread and therefore didn't have a run loop. But timers need to be scheduled on a run loop, and while the main thread has one, most background threads do not (unless you add one, yourself).

    To fix this, in that completion handler, dispatch the creation of the timer 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 doesn't 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()
    }
    

    For syntax for earlier version of Swift, see previous revision of this answer.

    0 讨论(0)
  • 2020-12-03 14:27

    This may sound obvious, but I had a similar problem, the timer just wouldn't fire and the reason is that it wasn't in the main thread...No errors, just never fired.

    Put in the main thread and at least you have a shot at it!

     DispatchQueue.main.async {
      //insert your timer here
    }
    
    0 讨论(0)
提交回复
热议问题