Many developers still get confused when they come across the word asynchronous. What does it mean? What is asynchronous programming? To understand what asynchronous programming is, we first need to understand its counterpart, synchronous programming. Let's use a playground to illustrate the difference.

Synchronous Programming

We add an import statement for the Foundation framework and define a URL for a remote resource. We use the URL to create a Data object and print the number of bytes in the Data object. The string FINISHED is printed to the console at the end of the playground.

import Foundation

let url = URL(string: "https://cdn.cocoacasts.com/7ba5c3e7df669703cd7f0f0d4cefa5e5947126a8/2.jpg")!

let data = try! Data(contentsOf: url)

print(data.count)

print("FINISHED")

Run the contents of the playground and inspect the output in the console. The number of bytes in the Data object is printed before the string FINISHED is printed. This isn't surprising since the statements of the playground are executed synchronously. The playground executes one statement at a time. The next statement is executed when the previous statement has finished executing. That is what makes synchronous programming easy to understand.

597628
FINISHED

Asynchronous Programming

Let's now take a look at asynchronous programming. We no longer create the Data object synchronously. We use Grand Central Dispatch, Apple's concurrency library, to create the Data object asynchronously.

import Foundation

let url = URL(string: "https://cdn.cocoacasts.com/7ba5c3e7df669703cd7f0f0d4cefa5e5947126a8/2.jpg")!

DispatchQueue.global().async {
    let data = try! Data(contentsOf: url)

    print(data.count)
}

print("FINISHED")

Run the contents of the playground. The output in the console illustrates the difference between synchronous and asynchronous programming. The print statement printing the string FINISHED precedes the print statement printing the number of bytes in the Data object.

FINISHED
597628

The statements of the playground are still executed synchronously with one exception. The closure that is passed to the async(_:) method of the global dispatch queue is executed asynchronously. This simply means that the closure is executed independently of the main playground flow.

Grand Central Dispatch submits the closure to a global dispatch queue and continues with the next statement in the playground. It doesn't wait for the statements in the closure to finish executing. At some point, the closure is executed and the print statement printing the number of bytes in the Data object is executed. That is why the print statement printing the string FINISHED comes first.

Pros and Cons

Asynchronous programming introduces complexity, but there's a very good reason why it's common in software development. Let's use an analogy to explore the pros and cons of synchronous and asynchronous programming.

You promised a few friends to cook them dinner. You keep things simple and prepare a main course and a cake for dessert. You create the batter for the cake and set it in the oven. It takes about an hour to bake the cake. You now have two options. The first option is to wait for the cake to finish baking. While you wait, there is nothing else you can do. The second option is preparing the main course while the cake is baking in the oven.

The first option is analogous to synchronous programming. The advantage is simplicity. You focus on one task at a time, which makes planning dinner easier. The second option is analogous to asynchronous programming. This option is more complex because there are several things happening at the same time. The advantage is speed. You can focus on the main course and bake the cake at the same time.

What's Next?

Asynchronous programming is essential if your goal is building a responsive, performant application. But, as I mentioned earlier, asynchronous programming introduces complexity. There are a number of risks you need to keep in mind. We cover these in more detail in Mastering Grand Central Dispatch.