Grand Central Dispatch (GCD) In iOS

Tudip

Tudip

01 May 2019

What is GCD (Grand Central Dispatch)?

Grand Central Dispatch is used in iOS to introduce concurrency and parallelism in the iOS applications, so that multiple heavy tasks are performed in the background, resulting in the smooth experience of the application usage, as the main thread is unaffected by the heavy background tasks.

GCD is introduced in iOS 4 to avoid the serial execution of the tasks as serial execution could be a pain.

Serial execution is not an ideal thing as one task is waiting for the processor until another task gets completed. What if the currently executing task is much heavy and the waiting task is pretty much small. Thus, what we get is a lot of waiting for our small task until the big one is finished.

Getting Started with Grand Central Dispatch (GCD)

GCD maintains tasks queues to operate them. Once a task is inserted in the queue it starts its execution. It’s up to us whether we want to start this task synchronously or asynchronously.

Following is the line to create a Dispatch Queue:

let dispatchQueue = DispatchQueue(label: "mydispatchqueue")

Once the DispatchQueue is created we can perform tasks synchronously or asynchronously (as per our need).

Types of DispatchQueue

    1. Main Queue

      When the system launches the iOS application then it creates a serial queue and binds that queue to the application’s main thread. We use this queue to mostly perform UI related updates in the application.
      You can use this queue by following:

      DispatchQueue.main.async {// Code to be executed}
    2. Global Queue

      There are four global concurrent queues which are provided and shared by the system.
      Quality of Service attribute indicates the priority of the tasks in the queue:
      User-interactive: We mostly use this queue to perform UI related updates. As per the apple’s guidelines, UI related tasks must not be done in a background thread. These are high priority tasks with relatively small size.
      Following line to create user interactive queue:

      DispatchQueue.global(qos: .userInteractive).sync {
      
      // Synchronous high priority queue
      
      }

      User-initiated: Tasks inside this queue must be run immediately as they react to user interaction events like reacting to a specific button click. Tasks within this queue are also counted as high priority tasks.
      Following line to create user initiated queue:

      DispatchQueue.global(qos: .userInitiated).sync {
      
      // Synchronous high priority queue
      
      }

      Utility: We use this queue to perform long-running operations in the background. These are low priority tasks like downloading a file come under this queue.
      Following line to create utility queue:

      DispatchQueue.global(qos: .utility).sync {
      
      // Asynchronous low priority queue
      
      }

      Background: Those tasks that take minutes to hours to complete come under this queue. These are heavy operations that perform in the background without affecting the app performance. Tasks like Backup, Indexing comes under this queue.
      Following line to create background queue:

      DispatchQueue.global(qos: .background).sync {
      // Asynchronous high priority queue
      }
    3. Custom Queue

      These are the dispatch queues which are created and maintained by the developer
      Custom queue are of two types:
      i) Serial Queue:
      – In Serial Queue Dispatch queue performs one task at a time.
      – To create a serial Dispatch Queue we need to create dispatch queue with “serial” tag.

      let mySerialQueue = DispatchQueue(label: "com.myapp.serialqueue", attributes: .serial)mySerialQueue.async {
      print("Step 1")
      }
      mySerialQueue.async {
      print("Step 2")
      }
      mySerialQueue.async {
      print("Step 3")
      }
      Result:
      Step 1
      Step 2
      Step 3

      As you can see that in the serial dispatch queue tasks are performed in the order in which they were inserted in the dispatch queue. That’s how the serial dispatch queue works.
      ii) Concurrent Queue:
      – In Concurrent Queue tasks were performed in parallel. We cannot determine which task will finish execution first.
      – To create a concurrent dispatchQueue we need to create dispatchQueue with concurrent tag.

      let myConcurrentQueue = DispatchQueue(label: "com.myapp.concurrentqueue", attributes: .concurrent)
      myConcurrentQueue.async {
      print("Step 1")
      }
      myConcurrentQueue.async {
      print("Step 2")
      }
      myConcurrentQueue.async {
      print("Step 3")
      }
      Result:
      We cannot determine the result of the concurrent queue as we have no idea which statement will finish its execution first.
      It could be:
      Step 3
      Step 1
      Step 2
      or could be:
      Step 2
      Step 1
      Step 3

Synchronous vs Asynchronous dispatch queue

In the synchronous execution, the program waits for the current work to finish before returning.

Following line is used for synchronous DispatchQueue:

let syncDispatchQueue = DispatchQueue(label: "com.myapp.customqueue")
syncDispatchQueue.sync {
// Code to be executed synchronously
}

In the asynchronous execution, the program returns immediately without waiting for the work to complete.

Following line is used for asynchronous DispatchQueue:

let asyncDispatchQueue = DispatchQueue(label: "com.myapp.customqueue")
asyncDispatchQueue.async {
// Code to be executed asynchronously
}

Request a quote