You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:30:23