Swift并发withCheckedContinuation
Swift并发withCheckedContinuation

Swift并发withCheckedContinuation

withCheckedContinuation 是 Swift Concurrency 提供的一个桥接工具,用于把基于回调(callback)的异步 API 转换为 async/await 形式。它通常用于把旧的异步代码(如闭包回调、delegate 方法、第三方库接口)包装成结构化并发函数。

Swift 并发希望异步函数结构为:

func foo() async -> T

但是系统和第三方库中仍然存在大量回调式API:

func foo(completion: @escaping (T?) -> Void)

这种API不能直接await,因此需要一个适配器,把“回调”转换成Swift并发希望的异步函数结构。

基本用法

简化原型:

func withCheckedContinuation<T>(
    _ body: (CheckedContinuation<T, Never>) -> Void
) async -> T

进入 withCheckedContinuation 时,函数会挂起(suspend)。

直到调用 resume(returning: value) 方法,value为返回值,才会恢复(resume)。

例如:

let value = await withCheckedContinuation { cont in
    asyncCallback { result in
        cont.resume(returning: result)
    }
}

当asyncCllback方法回调后,调用resume() 方法恢复并返回值。

使用示例

1、把回调 API 包装成 async 函数

func loadData() async -> String {
    await withCheckedContinuation { continuation in
        legacyAsyncCall { result in
            continuation.resume(returning: result)
        }
    }
}

2、错误场景使用 withCheckedThrowingContinuation

func fetchUser() async throws -> User {
    try await withCheckedThrowingContinuation { continuation in
        api.fetchUser { result in
            switch result {
            case .success(let user):
                continuation.resume(returning: user)
            case .failure(let error):
                continuation.resume(throwing: error)
            }
        }
    }
}

3、桥接任务闭包和回调闭包

例如TaskGroup是一个任务闭包(需要返回值),当调用loadFileRepresentation回调闭包(返回Void),两者的模型不匹配,导致无法通过loadFileRepresentation将值返回给TaskGroup:

group.addTask {
    provider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { url, error in
        guard let fileURL = url,
              let imageURL = FileUtils.saveURLToTempFile(fileURL: fileURL) else {
            return
        }
        return imageURL // 提示:Cannot convert value of type 'URL' to closure result type 'Void'
    }
}

提示原因为无法返回URL值,因为回调闭包返回的是Void。

两者需要使用 withCheckedContinuation 进行桥接,当 loadFileRepresentation 回调完成时,改为函数返回的形式:

group.addTask {
    return await withCheckedContinuation { cont in
        provider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { url, _ in
            guard let fileURL = url,
                  let imageURL = FileUtils.saveURLToTempFile(fileURL: fileURL) else {
                cont.resume(returning: nil)
                return
            }
            cont.resume(returning: imageURL)
        }
    }
}

注意事项

1、resume必须只调用一次。

2、必须确保所有分支都能恢复(调用resume方法),否则会挂起。

3、避免在continuation外再次调用resume方法。

4、错误示例:

// 多次 resume(禁止)
continuation.resume(returning: value)
continuation.resume(returning: value)

多次调用 resume 可能会导致警告或者崩溃。

总结

withCheckedContinuation 是一个安全桥接层,用于将回调式异步代码转换为 async/await。

当需要写成async API、包装成一次性完成的异步操作时,使用withCheckedContinuation。

在迁移旧代码或集成第三方库时保持结构化并发,同时通过“checked”机制降低并发错误风险。

相关文章

1、Swift Concurrency并发:https://fangjunyu.com/2025/05/15/swift-concurrency%e5%b9%b6%e5%8f%91/

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注