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

Swift Concurrency:如何处理执行中异步Task的完成回调更新?

用async/await实现可更新回调的异步任务

你需要处理异步任务的结果,核心问题是当任务处于执行中时调用方法,要更新完成回调。先回顾你给出的GCD实现:

func someFunc(completion: (() -> ())?) {
    if isLoading {
        if let completion {
            delayedCompletion = completion
        }
        return
    }
    isLoading = true
    delayedCompletion = completion

    // 模拟异步任务
    DispatchQueue.main.async { [weak self] in
        self?.delayedCompletion?()
        self?.delayedCompletion = nil
    }
}

这个GCD逻辑的核心是:如果任务已在执行,新的completion会覆盖旧的,最终只有最后设置的completion会被执行。


你写的async/await代码的问题

你提供的代码存在严重问题:当isLoading为true时,直接用新的CheckedContinuation覆盖delayedContinuation,导致之前调用someFunc()的异步任务会永久挂起——因为旧的Continuation被丢弃,永远不会被resume,这会造成内存泄漏和任务卡死。


修正后的实现(匹配GCD逻辑)

如果要和原GCD逻辑一致(仅最后一次调用的await能获取结果,之前的调用直接返回),可以这样修改:

首先定义属性:

private var isLoading = false
private var delayedContinuation: CheckedContinuation<Void, Never>?

然后实现someFunc():

func someFunc() async {
    if isLoading {
        // 先resume之前的continuation(让之前的调用结束),再保存新的
        let oldContinuation = delayedContinuation
        delayedContinuation = nil
        oldContinuation?.resume()
        
        return await withCheckedContinuation { [weak self] continuation in
            self?.delayedContinuation = continuation
        }
    }
    
    isLoading = true
    
    await withCheckedContinuation { [weak self] continuation in
        self?.delayedContinuation = continuation
        
        // 替换为实际的异步任务逻辑
        Task { @MainActor [weak self] in
            // 任务完成后恢复当前continuation
            self?.delayedContinuation?.resume()
            self?.delayedContinuation = nil
            self?.isLoading = false
        }
    }
}

另一种实现:让所有调用都收到结果

如果希望所有调用someFunc()的地方都能在任务完成后得到通知(而不是只保留最后一个),可以用数组存储所有Continuation:

private var isLoading = false
private var continuations = [CheckedContinuation<Void, Never>]()

func someFunc() async {
    if isLoading {
        await withCheckedContinuation { continuation in
            continuations.append(continuation)
        }
        return
    }
    
    isLoading = true
    
    await withCheckedContinuation { continuation in
        continuations.append(continuation)
        
        // 替换为实际的异步任务逻辑
        Task { @MainActor [weak self] in
            // 任务完成后恢复所有continuation
            self?.continuations.forEach { $0.resume() }
            self?.continuations.removeAll()
            self?.isLoading = false
        }
    }
}

关键注意点

  • 必须确保所有CheckedContinuation都被resume,否则会导致异步任务永久挂起,引发内存泄漏。
  • 使用[weak self]避免循环引用,尤其是在闭包和Task中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 21:57:37