How to use GCD (Grand Central Dispatch) in Swift? - Synchronous & Asynchronous Programming Tutorial

Note: If you are a beginner and you find it difficult to understand things written in this article. Feel free to ask questions on my Reddit page or Twitter.

Remember, you can do it. 😉


iPhone now contains multiple cores, and yet very few of us are using it the right way.

I know almost every one of us uses DispatchQueue, but that doesn't mean we are using it the right way. Even I didn't know the real benefits of DispatchQueue up until writing this article.

Many of us take our piece of hardware for granted and opt-out of concurrent programming, as there is so much power in new generation phones, we use now. But it’s important to understand that we need to structure our code to make use of the other cores of CPU.

By opting out of Concurrency, we are opting out of multi-core.

Using Thread in our code helps us execute our code simultaneously, and use multiple cores to make our app faster rather than wasting on our hardware resource. There are many more benefits which we will cover while learning Concurrent Programming.

It won't be possible for me to coverup everything about GCD in this article, so there will be many more following articles, where we'll be exploring more ways of using GCD and explore complicated concepts like Thread Explosion and Deadlock.

So don't forget to subscribe to stay updated about my new articles, as the only way to become a great iOS Developer is by learning.

Dispatch Queue

Dispatch Queue works in two main ways, which are synchronous execution & asynchronous execution.

Synchronous is used when you want to execute only one task at a time. Whereas, Asynchronous means that multiple tasks can be executed at a time regardless of the finishing time, which means if a task needs some time to perform, the other tasks will not have to wait for it to complete.

Most of us love Asynchronous programming, but we should always try to reason with the structure of the code we are going to write.

The syntax for both of them is below.

// Create a queue
let queue = DispatchQueue(label: "com.swiftpal.dispatch.tutorial")

// Synchronous Syntax
queue.sync {
    print("Sync task")
}

// Asynchronous Syntax
queue.async {
    print("Async Task")
}

Pretty simple, right?

Naming the queue is important, if your app crashes because of the queue, the crash log will report you the problem with the help of the name supplied to it, and it will end up helping yourself solve the problem.

Let’s go in-depth to understand the execution of both the ways of task execution.

Synchronous Programming - queue.sync { … }

Do it synchronously; if you reason with your code, then there can be many occasions where you could use queue.sync, making your cores work for you is beneficial for your application.

Let’s start by example.

let queue = DispatchQueue(label: "com.swiftpal.dispatch.synchronous")

// Task
queue.sync {
    Thread.sleep(forTimeInterval: 2) // Wait for 2 seconds
    print("Task 1 Done")
}

print("Task 2 Done")

/* Output:
 Task 1 Done
 Task 2 Done
*/

In the example above, you can see the Output received is in the order of code written, regardless of the queue.sync asking our second print statement to wait for two seconds.

Synchronous programming is widely used when you need to execute a task in the order you have written, maintaining the performance of the application.

Asynchronous Programming - queue.async { … }

I have seen a lot of developers using queue.async { … } on the note of it’s asynchronous, without understanding the use case, and it’s not right. It is essential to be able to distinguish where you need to use the synchronous function or asynchronous function.

Let’s move on to our async example.

let queue = DispatchQueue(label: "com.swiftpal.dispatch.asynchronous")

queue.async {
    Thread.sleep(forTimeInterval: 2) // Wait for 2 seconds.
    print("Task 1 Done")
}

print("Task 2 Done")

/* Output:
 Task 2 Done
 Task 1 Done
*/

You can see in the above example that unlike queue.sync, the order does not matter here, code is executed simultaneously regardless of queue.async taking longer to finish.

Bonus: Nested Queue

Suppose, you want update to update your UI after loading some data from the queue.async. How will you know it’s completed? You can’t update your UI other than the main thread, as your UI runs always on the main thread to provide you with a 60 fps seamless experience.

Let’s see what we can do.

let queue = DispatchQueue(label: "com.swiftpal.dispatch.nested")

queue.async {
    let list = Load.fromDatabase() // Loading some data from the database.
    
    DispatchQueue.main.async {  // Executing on main thread.
        self.tableView.reloadData() // Updating UI.
    }
}

Done

You can see that we have nested another queue after loading our list from the database to reload our imaginary Table View.

So, this was Synchronous & Asynchronous programming, next I have a bundle of GCD articles upcoming this week. So, if you liked this article, share it with your friends and subscribe to stay updated.

If you have any suggestions or questions, Feel free to connect me on Twitter. 😉

To Read Difference between Concurrent Queue and Serial Queue in Swift. Click here.

Difference between Concurrent Queue and Serial Queue (GCD - Grand Central Dispatch) in Swift

How to Format Data, and improve UX in Swift? - Part Two