一尘不染

为什么在块外而不是在块内设置时,`scheduledTimer`会正确启动?

swift

以下代码段在完成块外部调用时可以完美地工作,但是当我在完成块内部进行设置时,计时器永远不会触发。我不明白为什么会有区别:

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

最初在块外部调用它时,我没有使用自引用,但在内部调用它时,它是必需的。但是,我再次在块外测试了完全相同的代码,它仍然起作用。

该块是一个完成处理程序,在请求HealthKit相关信息的许可后被调用。


阅读 160

收藏
2020-07-07

共1个答案

一尘不染

问题在于所讨论的完成块可能未在主线程上运行,因此没有运行循环。但是计时器需要在运行循环中进行调度,而主线程只有一个,而大多数后台线程则没有(除非您自己添加一个)。

为了解决这个问题,在该完成处理程序中,将计时器的创建分派回主线程,并且应该可以正常工作:

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

或使用调度源计时器(可以为后台队列安排的计时器,并且不需要运行循环)。

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()
}
2020-07-07