为什么在块外设置时`scheduledTimer` 会正确触发,而不是在块内设置? [英] Why would a `scheduledTimer` fire properly when setup outside a block, but not within a block?

查看:18
本文介绍了为什么在块外设置时`scheduledTimer` 会正确触发,而不是在块内设置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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)
}

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆