Concurrency (Grand Central Dispatch) in Swift
Grand Central Dispatch
Multitasking allows us to run several tasks simultaneously. GCD (Grand Central Dispatch) is the simplest way to achieve multitasking in iOS.
Without GCD, in the past, we have done concurrency operations manually by creating the threads one by one. First, we create a thread on some core and give some tasks to execute.
GCD operates on dispatch queues through a class aptly named
DispatchQueue
. Queues can be either serial or concurrent.Serial queues guarantee that only one task runs at any given time. GCD controls the execution timing. Concurrent queues allow multiple tasks to run at the same time. The queue guarantees tasks start in the order you add them. Tasks can finish in any order.
Simple Task
First of all, we can just create a DispatchQueue
object with a label to execute something. It is done by .async
method on the queue.
Running Synchronous Tasks
When a task is completed, the other one continues to its execution which means tasks are handled in order.
Running Asynchronous Tasks
Asynchronous tasks are handled in any order. The execution of a task does not wait for the other to finish. They are executed simultaneously, but the order can be changeable according to the priority of the task. You will hear about what does the priority of a task queue is. Keep reading!
Concurrent Task Execution
We can create concurrent queues for task execution. In order to do that, we have to set attributes property of a queue to .concurrent
.
In concurrent mode, tasks in the queue get dispatched one after another and starts execution immediately and task completes their execution in any order.
Specifying Priority on Task Queues
The order of Quality of Service priority:
.userInteractive
-> We use this for UI updates, event handling and small workloads that require low latency. This should run on the main thread..userInitiated
-> We can use this when the user is waiting for results and for tasks which are required to continue user interaction. This runs in the high priority global queue..default
.utility
-> This represents long-running tasks such as a progress indicator which is visible during computations, networking, continuous data fetching, etc. This runs in the low priority global queue..background
-> This represents tasks that users are not aware of such as prefetching, maintenance, and other tasks that don’t require user interaction and aren’t time-sensitive. This has the lowest priority..unspecified
We created two dispatch queues with different quality of service. .userInitiated
property has the highest priority compared to .background
. Although we write queue2.async
block before queue1.async
block, queue1 task will finish earlier than the queue2.
Global Queue
We can use a global queue if we want to execute the task in the background like downloading a file, loading data or performing the search.
Main Queue
We should not perform UI related operations on a background queue or queue other than the main queue.
Delayed Task Queue Execution
GCD allows us to delay tasks by using a special method .asyncAfter
. To be more clear, we just print out the current date in an async after code block to see the 5-sec delay.
Dispatch Work Item
DispatchWorkItem
is nothing but a block of code which we can execute a task in any queue. Instead of writing a block of code, we can create a work item for task execution.
Concurrent Perform
DispatchQueue
provides us with a convenient method to execute the same task concurrently for several iterations.
Dispatch Group
Dispatch groups are a way to block a thread until one or more tasks finish executing. You can use this behaviour in places where you cannot make progress until all of the specified tasks are completed.
If we try to use it, .wait()
method of DispatchGroup item blocks the main queue, which means we cannot perform any UI related operation simultaneously. Again and again, Swift helps us to avoid this situation by using .notify()
method.
Thanks a lot, guys! If you have any questions, do not hesitate to ask. Keep learning!