在Swift中,Continuation
是在异步代码中将基于回调的异步函数转换为使用现代 Swift
的 async/await
语法的一种机制。这种机制主要通过 withCheckedContinuation
和 withCheckedThrowingContinuation
函数来实现。这两个函数可以帮助我们将传统的基于回调的异步 API 适配到 Swift
的 async/await
机制中。
withCheckedContinuation
withCheckedContinuation
主要用于处理不会抛出错误的异步操作。
import Foundation
func fetchData(completion: @escaping (String) -> Void) {
// 模拟一个异步操作,2秒后返回数据
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
completion("Fetched Data")
}
}
func fetchDataAsync() async -> String {
return await withCheckedContinuation { continuation in
fetchData { data in
// 当异步操作完成时,通过 continuation.resume 返回结果
continuation.resume(returning: data)
}
}
}
// 使用 `async` 和 `await` 调用
Task {
let data = await fetchDataAsync()
print(data) // 输出: Fetched Data
}
在上面的例子中,fetchData
是一个传统的异步函数,它通过回调的方式返回数据。为了让它适配 async/await
,我们使用了 withCheckedContinuation
函数。这个函数接受一个闭包,在闭包中我们会拿到一个 Continuation
对象,这个对象负责在异步任务完成时将结果返回。
在 fetchDataAsync
函数中,我们使用 withCheckedContinuation
来封装 fetchData
的回调。当 fetchData
的回调被触发时,我们调用 continuation.resume(returning: data)
来返回数据。
withCheckedThrowingContinuation
如果异步操作可能会抛出错误,那么可以使用 withCheckedThrowingContinuation
,它的用法和 withCheckedContinuation
类似,但它支持错误处理。
import Foundation
enum FetchError: Error {
case networkError
}
func fetchDataWithError(completion: @escaping (Result<String, FetchError>) -> Void) {
// 模拟一个异步操作,2秒后返回数据或错误
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
if Bool.random() {
completion(.success("Fetched Data"))
} else {
completion(.failure(.networkError))
}
}
}
func fetchDataAsyncWithError() async throws -> String {
return try await withCheckedThrowingContinuation { continuation in
fetchDataWithError { result in
switch result {
case .success(let data):
continuation.resume(returning: data)
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
// 使用 `async` 和 `await` 调用
Task {
do {
let data = try await fetchDataAsyncWithError()
print(data) // 如果成功输出: Fetched Data
} catch {
print("Failed to fetch data with error: \(error)")
}
}
在这个例子中,fetchDataWithError
函数模拟了一个可能会失败的异步操作,使用 Result
类型来返回成功或失败的结果。我们通过 withCheckedThrowingContinuation
来封装这个操作,以支持在 async/await
模式下使用。
当回调返回成功的结果时,我们调用 continuation.resume(returning: data)
;
如果回调返回了错误,我们则调用 continuation.resume(throwing: error)
。
注意事项
resume
只能调用一次: 一旦调用了resume
,这个continuation
对象就完成了其任务,不能再次调用,否则会导致运行时错误。withCheckedContinuation
和withCheckedThrowingContinuation
都是“检查的”: 这意味着 Swift 会对这些操作进行检查,确保你在使用它们时遵循了正确的调用约定(例如,resume
一定要被调用)。这有助于减少一些常见的异步编程错误。
总结
Continuation
是 Swift 中一种强大的机制,用于将传统的基于回调的异步代码转换为 async/await
模式。通过 withCheckedContinuation
和 withCheckedThrowingContinuation
,我们可以轻松地将已有的异步 API 适配到现代 Swift 异步编程模型中,使代码更简洁、更易读。
最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。