1. Writing clean code for Asynchronous operations

In this section, we will rewrite the code for App 11 (JSON API). We will have options for displaying, adding, deleting, and editing contacts using our same API (please refer to:11.1. The JSON API for the Contact App). We took small steps in11.8. Decluttering codes from View Controller (Recommended Read) section to separate the API calls from the control code. This time, we will break the chain of nested asynchronous API calls with async-await blocks of code to make our code cleaner.

1. Asynchronous calls

So far, what we have seen in our API calls is that, for a sequence of asynchronous tasks, we must wait for the previous task to complete before executing the next task. We wrote spaghetti code there and made the next API call from the callback of the first API call (if the response was a 200-level code, refer to 11.5. App11: Add a new Contact ). However, it renders our code largely unusable for future use. What if we could write the code such that we could call the async calls one after another, but the code would not execute in parallel? Wouldn't it be great to instruct the code to wait for the call to complete and then move to the next line? That way, we can keep our code cleaner and highly reusable for future use.

Let's examine an example using pseudocode.

So far, we have dealt with sequential API calls by calling the second API from within the callback of the first API. For example, in our contacts API, to add a new contact and display the updated list of contacts, what we are doing is:

//MARK: It is a pseudocode, not Swift!!!

func addANewContact(contact:Contact){
    callAddContactAPI(){ in response //This is async callback
        if response.statusCode == 200 {
            //A ton of other code....
            callGetAllContactsAPI() // The next API call
            //A ton of remaining code....
        }
    }
}

In this pseudocode, when we call the callAddContactAPI() API, we must also call the callGetAllContactsAPI() API from its callback. It creates a spaghetti of code. Think about 3 or more sequential calls; How complex would that be!

If we could write it the following way, would you feel it's better?

See how much more readable and usable it becomes!

So, we will do the same for App 11 here.

2. Tasks with async await

Let's look at the following Swift code (you can run it in a Playground):

Let's look at what we have here:

  1. On lines 6 through 9, we are writing a function that will asynchronously suspend for 5 seconds.

    1. To be able to run this asynchronous task and wait for it to complete, we need to call this function from a special block named Task{...} .

  2. On lines 13 to 17, we put the Task block.

    1. On line 14, we print the string, "Starting an asynchronous task..." to denote the start of the async task.

    2. On line 15, we are calling the async task, which will wait for the task to complete and fetch the greeting from the function. await notation means send this call to the background and wait in the scope of the Task block.

    3. On line 16, we print the greeting after the wait is over.

  3. On line 18, outside the Task block, we print, "Hello from synchronous world, I don't wait for the asyncs!"

Now, if we run the code, you will see the following:

Now, if we change the code like this:

We removed the print outside the Task block and put a new print statement in the block. It will ouput:

So, within the Task{...} block, all asynchronous calls are sequenced one after another! For better clarity, run the following code in your playground:

Important notes:

  1. When we define an async function in Swift, we write async notation on the declaration.

  2. When we call an async function, we call it using await notation.

  3. An await call can only be called from either another async function or from inside a Task{} block.

    1. There are other ways of handling and sequencing async calls; please do your own research on them. This is the simplest way to start with async sequencing.

Last updated

Was this helpful?