Skip to content

Instantly share code, notes, and snippets.

@lamprosg
Last active July 2, 2021 09:46
Show Gist options
  • Select an option

  • Save lamprosg/e629b91376ef65bb8a79c9983c5d35a8 to your computer and use it in GitHub Desktop.

Select an option

Save lamprosg/e629b91376ef65bb8a79c9983c5d35a8 to your computer and use it in GitHub Desktop.
(iOS) Swift 5.5. async await
// - 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