Swift concurrency 7 — Continuation的理解与使用(withCheckedContinuation、withCheckedThrowingContinuation)

在Swift中,Continuation 是在异步代码中将基于回调的异步函数转换为使用现代 Swiftasync/await 语法的一种机制。这种机制主要通过 withCheckedContinuationwithCheckedThrowingContinuation 函数来实现。这两个函数可以帮助我们将传统的基于回调的异步 API 适配到 Swiftasync/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 对象就完成了其任务,不能再次调用,否则会导致运行时错误。
  • withCheckedContinuationwithCheckedThrowingContinuation 都是“检查的”: 这意味着 Swift 会对这些操作进行检查,确保你在使用它们时遵循了正确的调用约定(例如,resume 一定要被调用)。这有助于减少一些常见的异步编程错误。

总结

Continuation 是 Swift 中一种强大的机制,用于将传统的基于回调的异步代码转换为 async/await 模式。通过 withCheckedContinuationwithCheckedThrowingContinuation,我们可以轻松地将已有的异步 API 适配到现代 Swift 异步编程模型中,使代码更简洁、更易读。

最后,希望能够帮助到有需要的朋友,如果觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值