By Maite Mañana

The wonders of async/await in iOS

 

For those who aren’t familiar with the concept of asynchronous tasks and how iOS handles them, async/await will be a painless and intuitive way to learn how to work with them. For those who have been fighting against this issue using completionHandlers, async/await is here to make your life much easier – and your asynchronous functions code much shorter. 

But async/await isn’t an iOS invention – not even the keywords they chose for this. This pattern has been around for a long time now and javascript – and its frameworks – have been using these keywords for a while as well. With Apple adopting this nomenclature, it is easier to map this solution throughout different programming languages. 

While the synchronous function will execute one command after the other and will not release the thread where it’s running until it has finished, an asynchronous function will release the thread while waiting on something to complete. For this, Swift uses closures, better known as completionHandlers. However, this approach has a few disadvantages: 

  • CompletionHandlers are not the most intuitive thing to understand if you are not familiar with closures. 
  • If you have at least one nested completionHandler (also known as pyramid of doom), all the indentation could make your code harder to read.
  • If you have some logic to do when you receive your response from the asynchronous call – even just checking for errors – you need to make sure to don’t forget to call the completionHandler before exiting your function (you wouldn’t want to leave it uninvoked!) and also to not call it more than once (this could cause unexpected behaviors). 

Thankfully, in Swift 5.5 Apple introduced async/await 🎉. To declare an asynchronous function, all you have to do it is to add the keyword async after the closing parenthesis of that function as follows:

To invoke an asynchronous function, you will need to add the keyword await in front of it: 

When doing this, you are indicating that your function may enter in suspended mode and release your thread back into the System (the same happens when you add the keyword throws as part of a function declaration: it may throw an error, but it may not). Your method will become active again when the asynchronous call finishes. Keep in mind that your function may not resume in the same thread that it was previously executing – it may, but it’s not guaranteed. 

Asynchronous functions can invoke one or more asynchronous functions as well: 

There is more, Swift 5.5 didn’t stop there! Properties can be declared as async as well – the only condition is that they need to be read-only:

In addition, Initializers can be asynchronous as well, and even for loops:

You must be wondering, how am I supposed to test all these asynchronous functions, right? Swift 5.5 has your back: XCTest supports async/await as well! You only need to add the keyword await as follows:

As you have seen, async/await has come to make our lives easier, Swift 5.5 covered lots of its bases to help you get started and it already provides alternatives for a bunch of their asynchronous APIs with this new approach.

If you want to know more about this topic, below there are some videos that will dive deeper into it:

 

Sources:

Apple (2021) Meet async/await in Swift from WWDC21: https://developer.apple.com/videos/play/wwdc2021/10132/

Hudson, Paul. (Jun, 2021) What’s new in Swift 5.5: https://www.youtube.com/watch?v=6C0SFPEy_0Y