If you have missed the introductory blog on the multithreading concept, please have look at that here
GCD is a low level API for managing concurrent operations. Apple introduced GCD to manage concurrency in an easier way. There is no overhead on the developers to create and manage threads manually. System will take care of creating and managing the threads.
There are three types of queues supported by GCD. These are the main building blocks of GCD.
Main Queue(serial queue)
Global Queue(concurrent queue)
Custom Queue(can be either a serial or concurrent queue)
1. Main Queue: Main queue is always associated with the main thread. This is where the UI activities must be performed. Main queue is a serial queue. If we block the main queue by running an expensive operation, the app will be frozen. This leads to a bad user experience.
Since the main queue is a serial queue, we should never dispatch a task synchronously to the main queue. Doing so will lead to a dead lock.
As we can see above, dispatching a task synchronously to a main queue will lead to the dead lock and the app will crash.
As we discussed above we must update the UI on the main queue. Even if you are highly experienced, there are times when you may miss updating the UI on the main thread. To avoid this, we can enable Main Thread Checker in the target scheme as shown below while testing/debugging and dis able while releasing the app.
Enable Main Thread Checker checkbox and run the project. If we are trying to update the UI on the background thread, we will see the warning as shown below.
2. Global queues
GCD provides global queues with different quality of service to perform expensive or time consuming operation. The expensive operations might be anything like downloading an image from the internet or image processing, etc. Global queue are also called the background queues.
Performing these expensive operations on the background queue will not put a load on the main queue making the app responsive.
Global queues are concurrent queues by default. In concurrent queue, multiple tasks can run on different threads. Tasks can be dispatched synchronously or asynchronously to the queue.
Let us discuss with some examples.
E.g 1: Dispatch sync to a global queue
As we can see above, dispatching synchronously to a global queue, will execute the tasks once the sync block is finished.
Here in the output section, we can see that first “Beginning” is printed. Then it executes the sync block which prints the numbers it will loop in a for loop. Next, it will print the “Second Set” statement. It will then execute the second sync block and finally it will print “End”.
E.g 2: Dispatch async to a global queue
As we can see above, It will first print the “Beginning” statement. Control will not wait for the async block to finish. It will print the “Second Set” and “End” statements. Finally async blocks will be executed.
There are 6 different types of quality of service supported by the global queues. One can make use of these different quality of service, simply called qos based on the requirement. This determines the priority at which the system allocates resources to the task. Higher the priority, higher will be the allocation of the system resource.
GCD also supports creating a custom queues. Custom queues can be either be a serial queue or a concurrent queue. If we create the queue with just label, it is a serial queue. We can also create a concurrent queue with the attributes set to .concurrent.
A custom queue can be created like below:
label: label is used to identify the custom queue. Preferred way is to create the label in a reverse DNS format.
qos: Quality of service of the queue.
attributes: if this is set to .concurrent, the will be a concurrent queue.
autorelease frequency: This indicates the frequency with which a dispatch queue autoreleases objects.
target: The target queue on which to execute blocks.