WatchOS应用声明第二个Timer后首个Timer停止触发问题求助
问题原因与解决方案
WatchOS 并没有限制只能使用单个 Timer,问题出在两个定时器的RunLoop 模式不匹配:
- 你用
Timer.publish创建的 timer1,指定运行在.main队列的.common模式下,这个模式会在 RunLoop 的大多数活跃场景(比如界面更新、后台任务)下正常触发。 - 而
Timer.scheduledTimer创建的 timer2,默认会加入当前 RunLoop 的.default模式。当 RunLoop 处理.default模式的任务时,会抢占资源,导致.common模式的 timer1 无法正常触发回调。
解决方案一:统一使用 Combine 风格的 Timer(推荐)
将 ObservableObject 中的 timer2 也改成 Timer.publish 实现,和 timer1 保持一致,避免 RunLoop 模式冲突:
class YourObservableObject: ObservableObject { private let timer2 = Timer.publish(every: 1, on: .main, in: .common).autoconnect() private var cancellables = Set<AnyCancellable>() init() { // 绑定定时器回调 timer2.sink { [weak self] _ in self?.invalidateOldData() } .store(in: &cancellables) } private func invalidateOldData() { // 你的失效旧数据逻辑 } }
这种方式自带内存管理(通过 cancellables 销毁定时器),还能和 SwiftUI 的响应式体系更好兼容。
解决方案二:将 timer2 加入 RunLoop 的 .common 模式
如果坚持使用 Timer.scheduledTimer,需要手动将定时器加入 .main 队列的 .common 模式,确保和 timer1 同模式运行:
class YourObservableObject: ObservableObject { private var timer2: Timer? func startTimer() { timer2 = Timer(timeInterval: 1, repeats: true) { [weak self] _ in self?.invalidateOldData() } // 手动加入common模式的RunLoop if let timer = timer2 { RunLoop.main.add(timer, forMode: .common) } } // 记得在对象销毁时销毁定时器,避免内存泄漏 deinit { timer2?.invalidate() } private func invalidateOldData() { // 你的失效旧数据逻辑 } }
注意要在对象销毁时调用 invalidate() 销毁 timer2,同时用 [weak self] 避免循环引用。
内容的提问来源于stack exchange,提问作者iMan Biglari
相关产品推荐
相关产品推荐

