NSTimer 被调度到线程的runloop。在问题代码中,GCD 调度的线程的 runloop 没有运行。您必须手动启动它,并且必须有退出运行循环的方法,因此您应该保留对 NSTimer 的引用,并在适当的时候使其无效。
NSTimer对target有强引用,所以target不能对timer有强引用,runloop对timer有强引用。
weak var weakTimer: Timer?
func configurateTimerInBackgroundThread(){
DispatchQueue.global().async {
// Pause program execution in Xcode, you will find thread with this name
Thread.current.name = "BackgroundThreadWithTimer"
// This timer is scheduled to current run loop
self.weakTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(runTimer), userInfo: nil, repeats: true)
// Start current runloop manually, otherwise NSTimer won't fire.
RunLoop.current.run(mode: .defaultRunLoopMode, before: Date.distantFuture)
}
}
@objc func runTimer(){
NSLog("Timer is running in mainThread: \(Thread.isMainThread)")
}
如果以后定时器失效了,在Xcode中再次暂停程序执行,你会发现那个线程已经消失了。
当然,GCD 调度的线程有runloop。GCD 在内部生成和重用线程,线程对调用者是匿名的。如果你觉得不安全,你可以使用 Thread. 不要害怕,代码很容易。
实际上,我上周尝试了同样的事情并与提问者同样失败,然后我找到了这个页面。在我放弃之前,我尝试了 NSThread。有用。那么为什么 GCD 中的 NSTimer 不能工作呢?它应该是。阅读runloop 的文档以了解 NSTimer 的工作原理。
使用 NSThread 与 NSTimer 一起工作:
func configurateTimerInBackgroundThread(){
let thread = Thread.init(target: self, selector: #selector(addTimerInBackground), object: nil)
thread.name = "BackgroundThreadWithTimer"
thread.start()
}
@objc func addTimerInBackground() {
self.weakTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(runTimer), userInfo: nil, repeats: true)
RunLoop.current.run(mode: .defaultRunLoopMode, before: Date.distantFuture)
}