为啥在块外设置时,`scheduledTimer` 会正确触发,而不是在块内?
Posted
技术标签:
【中文标题】为啥在块外设置时,`scheduledTimer` 会正确触发,而不是在块内?【英文标题】:Why would a `scheduledTimer` fire properly when setup outside a block, but not within a block?为什么在块外设置时,`scheduledTimer` 会正确触发,而不是在块内? 【发布时间】:2016-07-02 20:15:40 【问题描述】:以下代码 sn-p 在完成块外调用时可以正常工作,但是当我在块内设置计时器时,它永远不会触发。我不明白为什么会有区别:
self.timer = Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: #selector(self.foo),
userInfo: nil,
repeats: true)
最初在块外调用它时,我没有使用自引用,但一旦进入块内,它就被需要了。但是我再次在块外测试了完全相同的代码,它仍然有效。
block 是一个完成处理程序,在请求HealthKit
相关信息的权限后调用。
【问题讨论】:
【参考方案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()
有关 Swift 早期版本的语法,请参阅previous revision of this answer。
【讨论】:
感谢很有意义。我应该想到的。谢谢。 有没有理由不使用DispatchSourceTimer
而只使用计时器?
如果在主队列上运行,我经常倾向于Timer
,因为它很简单。但是,如果在后台队列上运行计时器,则调度计时器是正确的工具。【参考方案2】:
Timer() 可能不起作用的另一个原因是它是如何创建的。我有同样的问题,我尝试的一切都没有解决它,包括在主线程上实例化。我盯着这个看了很长一段时间,直到我(愚蠢地)意识到我正在以不同的方式创造它。而不是Timer.scheduledTimer
我用它实例化了它
let timer = Timer(timeInterval: 4.0, target: self, selector: #selector(self.timerCompletion), userInfo: nil, repeats: true)
就我而言,我必须将它实际添加到运行循环中才能运行。像这样
RunLoop.main.add(timer, forMode: RunLoop.Mode.default)
【讨论】:
【参考方案3】:这听起来很明显,但我遇到了类似的问题,计时器只是不会触发,原因是它不在主线程中......没有错误,只是从未触发。
放入主线程,至少你有一个机会!
DispatchQueue.main.async
//insert your timer here
【讨论】:
以上是关于为啥在块外设置时,`scheduledTimer` 会正确触发,而不是在块内?的主要内容,如果未能解决你的问题,请参考以下文章
【iOS13】为啥调用方法`retrieveConnectedPeripheralsWithServices:`不返回任何外设