为什么在一个块外部设置,而不是一个块内,`scheduledTimer`会正常触发? [英] 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.
该块是一个完成处理程序,在获得 HealthKit
相关信息。
The block is a completion hander that is called after asking permission for HealthKit
related information.
推荐答案
问题是有问题的完成块可能没有在主线程上运行,因此没有运行循环。但是定时器需要在运行循环上进行调度,而主线程有一个,大多数后台线程都没有(除非你自己添加一个)。
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)
}
或者使用调度源timer(可以为后台队列调度的计时器,不需要运行循环)。
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()
}
有关Swift早期版本的语法,请参阅此答案的前一版本。
For syntax for earlier version of Swift, see previous revision of this answer.
这篇关于为什么在一个块外部设置,而不是一个块内,`scheduledTimer`会正常触发?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!