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

Swift中如何失效DispatchWorkItem?录制计时器叠加问题咨询

问题分析与解决方案

你遇到的核心问题是:DispatchWorkItem的cancel()方法并不会主动中断正在执行的代码——它只是给这个work item打上「已取消」的标记,代码会继续执行,直到你主动检查这个标记并退出逻辑。这就是为什么你停止录制后旧的计时器还在跑,重启后又新增一个,最终导致叠加的原因。

为什么你的初始代码没用?

当你调用recordedTimeQueue?.cancel()时,那个正在后台跑的for循环并没有收到「停止」的指令,它会继续循环600次,每次更新文本。而你每次重启录制都会新建一个DispatchWorkItem,旧的还在后台运行,自然就出现了多个计时器同时更新的情况。

正确的解决方法

你编辑里的思路是对的——必须在循环内部检查work item的isCancelled状态,主动跳出循环。不过可以优化一下代码的安全性和可读性:

优化后的代码示例

// 声明全局/类级别的可选DispatchWorkItem
var recordedTimeQueue: DispatchWorkItem?

// 启动录制计时器的方法
func startRecordingTimer() {
    // 启动前先清理旧的计时器,避免叠加
    recordedTimeQueue?.cancel()
    recordedTimeQueue = nil
    
    recordedTimeQueue = DispatchWorkItem { [weak self] in
        guard let self = self else { return } // 避免循环引用,防止内存泄漏
        
        for i in 1..<600 {
            // 检查是否被取消,用可选绑定避免强制解包崩溃
            guard !(self.recordedTimeQueue?.isCancelled ?? true) else {
                break
            }
            
            // 用Swift原生的sleep方法替代usleep,可读性更好
            Thread.sleep(forTimeInterval: 1)
            
            DispatchQueue.main.async {
                self.recordedTime?.text = "\(i)"
            }
        }
    }
    
    // 执行work item
    DispatchQueue.global().async(execute: recordedTimeQueue!)
}

// 停止录制时调用的方法
func stopRecording() {
    print("recording stopped")
    recordedTimeQueue?.cancel()
    recordedTimeQueue = nil // 彻底清空,确保下次启动是全新的计时器
}

关键优化点说明

  • 启动前清理旧计时器:每次启动新计时器前,先取消并清空旧的recordedTimeQueue,从根源避免叠加问题。
  • 安全检查isCancelled:用?? true做默认值,即使recordedTimeQueue已经被置为nil,也能安全退出循环,不会因为强制解包(!)导致崩溃。
  • 避免循环引用:在work item里用[weak self]和可选绑定guard let self = self,防止因为work item持有self导致的内存泄漏。
  • 更优雅的延时:用Thread.sleep(forTimeInterval: 1)替代usleep(1000000),两者都是阻塞线程1秒,但前者是Swift原生API,可读性更强。

额外补充:为什么必须自己检查取消状态?

GCD设计成这样是为了线程安全——强制中断正在执行的代码可能会导致资源泄漏、数据不一致等问题。所以它只提供「标记取消」的机制,让开发者自己在合适的时机(比如循环的每次迭代)检查状态并主动退出,这样能保证代码的可控性和安全性。

内容的提问来源于stack exchange,提问作者Chewie The Chorkie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:57:18