GCD, or Grand Central Dispatch, is the main system of threading used in iOS and Mac software. It works on a concept of queues, abstracting away threads. As the programmer, you don’t handle creating and deciding which tasks should run of which threads, instead you give them to a queue and iOS handles that for you.
GCD is Apple’s wrapper for the C lib_dispatch library. There are 6 global queues, as well as the UI queue, called main. A concurrent queue is one that has multiple threads attached to it, where a serial queue is a queue with only one thread, such as the main queue. Since the main queue is serial with one thread, it’s often referred to as the main thread. Serial GCD queues are First In First Out, so tasks start in the order that they arrive. The non-main, global queues are concurrent – they create and manage multiple threads. If you run a task sync on a concurrent queue, it can continue running other tasks on one of its other threads. This means that tasks on concurrent queues can finish in a different order than they started.
You can also create your own private queues, providing a label as well as optional attributes, such as whether it’s a concurrent or serial queue. A queue you create yourself is serial by default. Apple abstracts thread priorities to a concept called Quality of Service. You specify the purpose of the queue/task, and let the scheduler decide how to juggle it. In Swift, this is an enum, consisting of:
.userInteractive – Tasks the user is directly interacting with
.userInitiated – Tasks initiated by the UI that the user need immediately but can be async
.default – No explicit or inferred QOS
.utility – Long running tasks with progress indicators (I/O, networking).
.background – Tasks the user is not directly aware of (not time sensitive)
.unspecified
You can access one of these queues with the following function:
You should push work to a new thread with .async {}, which starts the task asynchronously and then immediately returns, and update the UI by calling DispatchQueue.main.async {}. You should use .sync {} only when you want to suspend the current queue until a short running task has completed, such as getting and setting a value. It’s mainly used for thread safety to avoid race conditions.
Never dispatch synchronously onto the current queue, as it will cause deadlock. Also, never dispatch synchronously from the main queue, as this will block UI updates.
To recap:
Concurrent queues are queues that handle multiple threads.
Serial queue only handle one thread.
Because tasks on concurrent queues can execute together on the multiple threads the queue handles, although you might put tasks in in a certain order, they probably won’t come out in that order.
Tasks on serial queue are FIFO, so they come out in the order they went in.
The only serial queue that DispatchQueue gives you is .main, but you shouldn’t use that for long running tasks. Instead, you can create your own private queue, and by default, serial is the default attribute.