我有这样的代码来调用计时器计划方法。到目前为止,我从未遇到过调用计时器方法的问题。我什至没有使用过 RunLoop。
private func expireToken(afterTimeInterval timeInterval: TimeInterval) {
print("[DEBUG] Schedule expiration, time: \(timeInterval), main thread \(Thread.isMainThread)")
let timer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: false) { timer in
print("[DEBUG] Expiring token")
self.tokenContainer = .expired
timer.invalidate()
}
RunLoop.current.add(timer, forMode: .common)
}
此方法似乎是从后台线程调用的,作为第一个打印语句日志来控制台此类信息
[DEBUG] Schedule expiration, time: 10.0, main thread false
Timer 只能调度在正在处理的 RunLoop 上(定期调用
run...
方法之一)。大多数线程不处理 RunLoop。
通常,对于您所描述的内容,正确的答案是在主运行循环上运行计时器。定时器本身非常便宜。
借助 Swift 并发,您还可以通过任务和
Task.sleep
轻松完成此操作。这将让您.cancel()
完成任务,就像您.invalidate()
计时器一样。
您还可以使用
DispatchQueue.asyncAfter
在给定时间后运行某些内容,而无需计时器。
最后,如果您确实需要处理自己的后台 RunLoop,请参阅《线程编程指南》中的 Run Loops。然而,这很少需要。