Last active
July 2, 2021 09:46
-
-
Save lamprosg/e629b91376ef65bb8a79c9983c5d35a8 to your computer and use it in GitHub Desktop.
(iOS) Swift 5.5. async await
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // - OLD WAY | |
| func fetchWeatherHistory(completion: @escaping ([Double]) -> Void) { | |
| // Complex networking code here; we'll just send back 100,000 random temperatures | |
| DispatchQueue.global().async { | |
| let results = (1...100_000).map { _ in Double.random(in: -10...30) } | |
| completion(results) | |
| } | |
| } | |
| func calculateAverageTemperature(for records: [Double], completion: @escaping (Double) -> Void) { | |
| // Sum our array then divide by the array size | |
| DispatchQueue.global().async { | |
| let total = records.reduce(0, +) | |
| let average = total / Double(records.count) | |
| completion(average) | |
| } | |
| } | |
| func upload(result: Double, completion: @escaping (String) -> Void) { | |
| // More complex networking code; we'll just send back "OK" | |
| DispatchQueue.global().async { | |
| completion("OK") | |
| } | |
| } | |
| // - USING IT | |
| fetchWeatherHistory { records in | |
| calculateAverageTemperature(for: records) { average in | |
| upload(result: average) { response in | |
| print("Server response: \(response)") | |
| } | |
| } | |
| } | |
| // - NEW WAY | |
| /* - Problems adddressed | |
| * It’s possible for those functions to call their completion handler more than once, or forget to call it entirely. | |
| * The parameter syntax @escaping (String) -> Void can be hard to read. | |
| * At the call site we end up with a so-called pyramid of doom, with code increasingly indented for each completion handler. | |
| * Until Swift 5.0 added the Result type, it was harder to send back errors with completion handlers. | |
| */ | |
| //From Swift 5.5, we can now clean up our functions by marking them as asynchronously returning a value, like this: | |
| func fetchWeatherHistory() async -> [Double] { | |
| (1...100_000).map { _ in Double.random(in: -10...30) } | |
| } | |
| func calculateAverageTemperature(for records: [Double]) async -> Double { | |
| let total = records.reduce(0, +) | |
| let average = total / Double(records.count) | |
| return average | |
| } | |
| func upload(result: Double) async -> String { | |
| "OK" | |
| } | |
| // - USING NEW WAY | |
| func processWeather() async { | |
| let records = await fetchWeatherHistory() | |
| let average = await calculateAverageTemperature(for: records) | |
| let response = await upload(result: average) | |
| print("Server response: \(response)") | |
| } | |
| // RULES | |
| /* | |
| * Synchronous functions cannot simply call async functions directly – it wouldn’t make sense, so Swift will throw an error. | |
| * Async functions can call other async functions, but they can also call regular synchronous functions if they need to. | |
| * If you have async and synchronous functions that can be called in the same way, | |
| - Swift will prefer whichever one matches your current context | |
| – if the call site is currently async then Swift will call the async function, otherwise will call the synchronous one. | |
| */ | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment