I am trying to convert my working completions handler functions to the new async/await syntax, but I have a problem finding the right syntax for a function which uses a generic parameter (T):
What I used before and works:
typealias CurrentWeatherCompletionHandler = (CurrentWeather?, Error?) -> Void
private func weatherDownload<T: Codable>(weatherType: String, completionHandler completion: @escaping (_ object: T?,_ error: Error?) -> ()) {
let storage = Storage.storage()
let pathReference = storage.reference(withPath: "\(weatherType)" "-de.json")
pathReference.getData(maxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
print("Error beim \(weatherType) Download: \(error)")
completion(nil, error)
} else {
do {
let weather = try self.decoder.decode(T.self, from: data!)
completion(weather, nil)
} catch let error {
completion(nil, error)
}
}
}
}
func getCurrentWeather(completionHandler completion: @escaping CurrentWeatherCompletionHandler) {
weatherDownload(weatherType: Constants.currentWeatherFolder) { (weather: CurrentWeather?, error) in
completion(weather, error)
}
}
What I tried, but didn't work:
private func weatherDownload<T: Codable>(weatherType: String) async -> (weather: T?, error: Error?) {
//same network code as before but with return instead of completion:
return (weather, nil) // Compiler Error: 'nil' requires a contextual type / Unexpected non-void return value in void function
}
func getCurrentWeather() async -> (weather: CurrentWeather?, error: Error?) {
return await weatherDownload(weatherType: Constans.currentWeatherFolder)
}
Any idea is welcome.
CodePudding user response:
Essentially, if the SDK you're using does not support the Concurrency API, the only way you can use it is by calling withCheckedContinuation
or withCheckedThrowingContinuation
(for error handling). The problem with your code is either the problem I mentioned, and / or the fact that Swift does not properly infer the T
type from the return type.
The following pattern should hopefully work for you:
private func weatherDownload<T: Codable>(_ type: T.Type, weatherType: String) async throws -> T {
return try await withCheckedThrowingContinuation { continuation in
// Your original code from before,
// with the following difference instead of calling the completion handler:
...
do {
let weather = try self.decoder.decode(T.self, from: data)
continuation.resume(returning: weather)
} catch {
continuation.resume(throwing: error)
}
}
}
For more information regarding this pattern, check out these links: link1, link2