简体   繁体   中英

Create async/await function with Generic Parameter

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM