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

Swift中如何将已有异步任务封装进DispatchWorkItem实现可取消?

为外部异步方法封装取消功能(基于DispatchWorkItem)

给定一个无法修改内部实现的SomeClass,其异步方法someFunc会在后台完成后调用传入的completion回调。要在外部为这类任务添加取消能力,用DispatchWorkItem的封装方案如下:

核心思路

通过外部封装类持有DispatchWorkItem,将原异步方法的调用逻辑包裹在WorkItem中,同时在原方法的completion回调里检查WorkItem的取消状态,决定是否将结果传递给上层调用者——这样即使底层异步任务已经启动,也能避免执行已取消任务的后续回调逻辑。

代码实现

// 对应原问题的参数和结果类型(示例定义)
struct SomeParams {}
struct SomeResult {}

// 原有的无法修改的类
class SomeClass {
    func someFunc(params: SomeParams, completion: ((SomeResult) -> ())?) {
        // 模拟原异步逻辑(实际可能是网络请求、耗时计算等)
        DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
            completion?(SomeResult())
        }
    }
}

// 外部封装的任务管理类
class AsyncTaskWrapper {
    private var workItem: DispatchWorkItem?
    
    /// 启动异步任务
    /// - Parameters:
    ///   - params: 原方法需要的参数
    ///   - someInstance: SomeClass的实例
    ///   - completion: 上层调用者的回调,result为nil表示任务已取消
    func startTask(with params: SomeParams, using someInstance: SomeClass, completion: @escaping (SomeResult?) -> Void) {
        // 创建WorkItem,包裹原方法的调用逻辑
        let item = DispatchWorkItem { [weak self] in
            someInstance.someFunc(params: params) { result in
                // 检查任务是否已取消,取消则不执行后续回调
                guard let self = self, !self.workItem!.isCancelled else {
                    completion(nil)
                    return
                }
                completion(result)
            }
        }
        
        workItem = item
        // 将WorkItem提交到队列执行
        DispatchQueue.global().async(execute: item)
    }
    
    /// 取消当前任务
    func cancelTask() {
        workItem?.cancel()
        workItem = nil
    }
}

使用示例

let wrapper = AsyncTaskWrapper()
let someInstance = SomeClass()

// 启动任务
wrapper.startTask(with: SomeParams(), using: someInstance) { result in
    if let result = result {
        print("任务完成,结果:\(result)")
    } else {
        print("任务已取消")
    }
}

// 取消任务(比如用户点击取消按钮时调用)
// wrapper.cancelTask()

注意事项

  • 这种封装无法终止已经启动的底层异步任务(比如已经发出的网络请求),只能拦截回调逻辑——这是在不修改SomeClass内部的前提下的可行方案,因为外部无法直接干预底层任务的执行流程。
  • 用[weak self]避免AsyncTaskWrapper和DispatchWorkItem之间的循环引用,确保内存能正常释放。

内容的提问来源于stack exchange,提问作者Gargo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 03:04:57