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/
