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

带泛型参数的Completion Handler函数转换为async/await语法的实现疑问

解决Swift泛型Completion Handler转async/await的问题

你的核心问题在于没有贴合Swift async/await的错误处理范式,同时没有正确将回调式的Storage API桥接到异步语法上。我们一步步来修正:

错误原因分析

  1. 错误处理方式不符合async/await规范:你试图用元组(weather: T?, error: Error?)同时返回结果和错误,但Swift的async函数设计是成功时返回值,失败时抛出错误,这种元组方式会导致类型推断混乱(比如编译器不知道nil对应的具体类型)。
  2. 未正确转换回调API:原代码中的getData是回调式的,你直接改成返回值会导致编译器报错“Unexpected non-void return value in void function”——因为回调闭包本身是无返回值的,不能直接在里面return结果。

正确的重构方案

我们需要用withCheckedThrowingContinuation把回调式的API包装成async/await风格,同时用throws处理错误:

1. 重构泛型下载函数

// 可以先定义自定义错误,让错误处理更清晰
enum WeatherDownloadError: Error {
    case noDataReceived
    case decodingFailed(Error)
}

private func weatherDownload<T: Codable>(weatherType: String) async throws -> T {
    let storage = Storage.storage()
    let pathReference = storage.reference(withPath: "\(weatherType)-de.json")
    
    // 用withCheckedThrowingContinuation桥接回调到async/await
    let data = try await withCheckedThrowingContinuation { continuation in
        pathReference.getData(maxSize: 1 * 1024 * 1024) { data, error in
            if let error = error {
                // 传递Storage的错误
                continuation.resume(throwing: error)
                return
            }
            
            guard let data = data else {
                // 处理data为nil的情况,抛出自定义错误
                continuation.resume(throwing: WeatherDownloadError.noDataReceived)
                return
            }
            
            // 传递成功获取到的数据
            continuation.resume(returning: data)
        }
    }
    
    // 解码数据,捕获解码错误并转换为自定义错误
    do {
        return try decoder.decode(T.self, from: data)
    } catch let decodingError {
        throw WeatherDownloadError.decodingFailed(decodingError)
    }
}

2. 重构获取当前天气的函数

func getCurrentWeather() async throws -> CurrentWeather {
    // 直接调用泛型函数,编译器会自动推断T为CurrentWeather
    return try await weatherDownload(weatherType: Constants.currentWeatherFolder)
}

3. 调用方式示例

使用do-catch处理异步错误:

// 在async函数内调用
do {
    let currentWeather = try await getCurrentWeather()
    // 处理成功获取到的天气数据
    print(currentWeather)
} catch {
    // 处理所有可能的错误
    switch error {
    case WeatherDownloadError.noDataReceived:
        print("Error: 未获取到天气数据")
    case WeatherDownloadError.decodingFailed(let innerError):
        print("解码失败: \(innerError)")
    default:
        print("Storage错误: \(error)")
    }
}

关键说明

  • withCheckedThrowingContinuation:这是Swift标准库提供的工具,用于将传统的回调式API转换为async/await风格。它通过resume方法来传递成功的返回值或抛出的错误。
  • 错误处理:async/await依赖Swift的throws机制,相比回调式的错误元组,这种方式更符合Swift的类型安全原则,代码可读性也更高。
  • 泛型推断:调用weatherDownload时,编译器会根据getCurrentWeather的返回值自动推断泛型参数T为CurrentWeather,不需要手动指定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 21:32:43