Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
323 views
in Technique[技术] by (71.8m points)

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

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 there is a difference:

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

I was not using the self references when calling it initially outside the block, but then once inside, it was required. However I tested the exact same code outside the block again and it does still work.

The block is a completion hander that is called after asking permission for HealthKit related information.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...