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
相关产品推荐
相关产品推荐

