使用DispatchSource.makeTimerSource()创建的定时器未触发问题排查
排查DispatchSourceTimer未触发的问题
我帮你梳理下代码里的几个关键问题,这些都会导致定时器无法正常触发:
1. 初始化时过早调用cancel()
你在创建定时器后立刻调用了timer?.cancel(),这会直接把定时器推入终态,后续再调用schedule也无法让它恢复工作了。DispatchSourceTimer一旦被cancel,就不能再复用,必须重新创建。
2. repeating参数未完整设置
代码里的repeating:...是不完整的语法,你需要指定一个有效的时间间隔(比如.seconds(1)表示每秒重复一次),否则编译器都无法通过,更别说运行了。
3. 未调用resume()启动定时器
DispatchSourceTimer创建后默认处于**suspended(挂起)**状态,必须手动调用resume()才能让它开始计时触发事件。
4. 状态管理逻辑缺失
你的State枚举定义了,但没有在初始化和操作时正确维护状态,这会导致后续调用start/stop时可能出现重复resume或suspend的错误(重复resume会崩溃)。
修正后的完整代码
import Foundation import Dispatch class RepeatingTimer { private var timer: DispatchSourceTimer? private let queue: DispatchQueue var eventHandler: (() -> Void)? private enum State { case none case suspended case resumed } private var state: State = .none init() { queue = DispatchQueue(label: "serial.queue.1") // 移除初始化时的cancel调用 timer = DispatchSource.makeTimerSource(queue: queue) state = .suspended // 初始化后标记为挂起状态 } // 添加启动定时器的方法 func start() { guard state != .resumed else { return } // 确保定时器未被cancel,若已cancel则重新创建 if timer == nil { timer = DispatchSource.makeTimerSource(queue: queue) } // 完整设置触发时间和重复间隔 timer?.schedule(deadline: .now() + .seconds(1), repeating: .seconds(1)) // 设置事件处理闭包 timer?.setEventHandler { [weak self] in self?.eventHandler?() } timer?.resume() state = .resumed } // 添加停止定时器的方法 func stop() { guard state == .resumed else { return } timer?.suspend() state = .suspended } // 销毁时确保取消定时器,避免内存泄漏 deinit { timer?.cancel() timer = nil } } // 使用示例 let timer = RepeatingTimer() timer.eventHandler = { print("定时器触发了!") } timer.start() // 保持程序运行(命令行环境下需要) RunLoop.main.run(until: .now() + .seconds(5))
关键注意点
- 永远不要在定时器未启动时调用
cancel(),除非你确定不再使用它。 - 必须通过
resume()和suspend()来控制定时器的启停,避免直接操作timer的状态导致崩溃。 - 使用
[weak self]在事件处理闭包中,避免循环引用导致内存泄漏。
内容的提问来源于stack exchange,提问作者John Difool
相关产品推荐
相关产品推荐

