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

如何将非典型完成处理程序转换为Swift Concurrency语法?

Swift Concurrency 转换:处理同时返回值和错误的场景

原来基于完成回调的异步方法里,你遇到了「缓存过期但网络不可用时,同时返回缓存值和CacheError.outdatedCache错误」的场景,但Swift Concurrency的async throws模式本身是二选一的逻辑:要么成功返回值,要么抛出错误,没法同时传递两者。所以不能直接套用常规的withCheckedThrowingContinuation写法,得通过调整返回类型来解决。

下面是两种可行的方案:

方案一:自定义结果结构体承载值和可选错误

直接定义一个结构体,把数据和可能的缓存错误打包在一起返回,不需要使用throws:

// 先定义你的缓存错误类型
enum CacheError: Error {
    case outdatedCache
    // 其他缓存相关错误...
}

// 自定义结果结构体
struct CacheResult<T> {
    let data: T
    let cacheError: CacheError?
}

// 转换后的异步方法
func fetchData() async -> CacheResult<Data> {
    return await withCheckedContinuation { continuation in
        // 调用原来的基于完成回调的方法
        legacyFetchData { data, error in
            // 这里假设data非空(你的场景下缓存过期时也有值)
            let result = CacheResult(
                data: data!,
                cacheError: error as? CacheError
            )
            continuation.resume(returning: result)
        }
    }
}

调用时可以同时获取数据和缓存状态:

let result = await fetchData()
// 使用拿到的数据
processData(result.data)
// 处理缓存过期的提示
if result.cacheError == .outdatedCache {
    showExpiredCacheWarning()
}

方案二:用枚举明确区分不同状态

如果想更清晰地表达「正常成功」「过期缓存」「完全失败」这几种场景,可以用枚举来封装结果:

enum FetchResult<T> {
    case success(T)               // 正常拿到最新数据
    case outdatedCache(T)         // 缓存过期,但返回缓存数据
    case failure(Error)           // 完全获取失败,无数据
}

// 转换后的异步方法
func fetchData() async -> FetchResult<Data> {
    return await withCheckedContinuation { continuation in
        legacyFetchData { data, error in
            if let data = data {
                if let cacheError = error as? CacheError, cacheError == .outdatedCache {
                    continuation.resume(returning: .outdatedCache(data))
                } else {
                    continuation.resume(returning: .success(data))
                }
            } else if let error = error {
                continuation.resume(returning: .failure(error))
            } else {
                // 处理极端情况:data和error都为空
                continuation.resume(returning: .failure(CacheError.unknown))
            }
        }
    }
}

调用时通过switch分支处理不同状态:

switch await fetchData() {
case .success(let data):
    processData(data)
    hideExpiredWarning()
case .outdatedCache(let data):
    processData(data)
    showExpiredCacheWarning()
case .failure(let error):
    showFetchFailureAlert(error)
}

关键说明

之所以不能用async throws直接处理,是因为throws的语义是「操作失败,无法返回有效结果」,但你的场景是「操作虽然有警告(缓存过期),但仍有可用结果」,这不符合throws的设计意图。所以必须通过自定义返回类型,把「结果数据」和「状态/警告」打包在一起传递。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 22:56:30