带泛型参数的Completion Handler函数转换为async/await语法的实现疑问
解决Swift泛型Completion Handler转async/await的问题
你的核心问题在于没有贴合Swift async/await的错误处理范式,同时没有正确将回调式的Storage API桥接到异步语法上。我们一步步来修正:
错误原因分析
- 错误处理方式不符合async/await规范:你试图用元组
(weather: T?, error: Error?)同时返回结果和错误,但Swift的async函数设计是成功时返回值,失败时抛出错误,这种元组方式会导致类型推断混乱(比如编译器不知道nil对应的具体类型)。 - 未正确转换回调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
相关产品推荐
相关产品推荐

