GCD in swift

ref – http://www.appcoda.com/grand-central-dispatch/

Queue

A queue is actually a block of code that can be executed synchronously or asynchronously, either on the main or on a background thread.

Once a queue is created, the operating system is the one that manages it and gives it time to be processed on any core of the CPU.

Multiple queues are managed accordingly, and that management is something that developers don’t have to deal with.

Queues are following the FIFO pattern (First In, First Out), meaning that the queue that comes first for execution will also finish first (think of it like a queue of humans waiting in front of the counter, the first one is served first, the last one is served last).

Work Item

A work item is literally a block of code that is either written along with the queue creation, or it gets assigned to a queue and it can be used more than once (reused). It’s the code that a dispatch queue will run. The execution of work items in a queue also follows the FIFO pattern.

This execution can be synchronous or asynchronous.

In the synchronous case, the running app does not exit the code block of the item until the execution finishes. Thus, when the execution is happening, the running app does not exit, and this results in the UI being frozen for a little while.

On the other hand, when queues are scheduled to run asynchronously, then the running app calls the work item block and it returns at once and continue with its main thread. Thus you will not see pauses on the UI.

Example 1

The sync will process its display of 0 to 10, and you’ll notice that you won’t be able to click on the UI button. That’s because the block of code is being processed by the queue in a sync fashion. You’ll have to wait until it completes. Then you’ll notice that your button presses will take effect.

Result:

–viewDidLoad–
button created
view hieararchy added button
— SLEEP! —
 0
— SLEEP! —
 1
— SLEEP! —
 2
— SLEEP! —
 3
— SLEEP! —
 4
— SLEEP! —
 5
— SLEEP! —
 6
— SLEEP! —
 7
— SLEEP! —
 8
— SLEEP! —
 9
Button Clicked
Button Clicked
Button Clicked
Button Clicked
Button Clicked
Button Clicked
Button Clicked

source code

Change sync to async

Now let’s change the sync into an async. You’ll see that your button now has effect while the tasks are being processed.

Output:

–viewDidLoad–
button created
view hieararchy added button
Button Clicked
 0
Button Clicked
Button Clicked
Button Clicked
 1
Button Clicked
Button Clicked
 2
 3
Button Clicked
 4
 5
 6
 7
Button Clicked
Button Clicked
Button Clicked
Button Clicked
 8
Button Clicked
 9

The important here is to make clear that our main queue is free to “work” while we have another task running on the background, and this didn’t happen on the synchronous execution of the queue.

Qos – Quality of Service (enum)

output:
–viewDidLoad–
button created
view hieararchy added button
Œ 0
Á 0
Œ 1
Á 1
Á 2
Œ 2
Á 3
Œ 3
Á 4
Œ 4
Œ 5
Á 5
Œ 6
Á 6
Œ 7
Á 7
Œ 8
Á 8
Œ 9
Á 9

It’s easy to say by looking at the above screenshot that both tasks are “evenly” executed, and actually this is what we expect to happen.

Now change priority of queue2 to DispatchQoS.utility

The first dispatch queue (queue1) will be executed faster than the second one, as it’s given a higher priority. Even though the queue2 gets an opportunity of execution while the first one is running, the system provides its resources mostly to the first queue as it was marked as a more important one. Once it gets finished, then the system takes care of the second queue.

Make sure you change the index i and j to 100, instead of 10. Then run it, you’ll see that are about the same…until when the index gets into the 20s. For my machine, at around index 25, 26, queue1 runs twice, which hints that queue1 gets more of attention.

Now let’s change queue1 to background. Let’s change queue2 back to userInitiated.

If you were to run the code again, you’ll see that queue2 (having the higher priority) will finish a full 6 indexes faster than queue1.

The common thing to all the previous examples is the fact that our queues are serial. That means that if we would assign more than one tasks to any queue, then those tasks would have been executed one after another, and not all together.

Concurrent Queues

There’s a new argument in the above initialisation: The attributes parameter. When this parameter is present with the concurrent value, then all tasks of the specific queue will be executed simultaneously. If you don’t use this parameter, then the queue is a serial one. Also, the QoS parameter is not required, and we could have omitted it in this initialisation without any problem.

We have one concurrent queue (called anotherQueue), and it runs 3 tasks. All three tasks are executed at the same time (concurrently), running through their own perspective for loops.

User Activated

The attributes parameter can also accept another value named initiallyInactive. By using that, the execution of the tasks doesn’t start automatically, instead the developer has to trigger the execution.

Delaying the Execution

You can activate when you want your queue to start executing. This is done by creating a dispatch queue, then assigning a property reference to it. Once you do that, you can use the property reference to call the activate method wherever you like in your class.

Notice that you assign serial, concurrent, and initiallyInactive characteristics via an array on the attributes property when creating DispatchQueue.

Accessing the Main and Global Queues

In all the previous examples we manually created the dispatch queues we used. However, it’s not always necessary to do that, especially if you don’t desire to change the properties of the dispatch queue. As I have already said in the beginning of this post, the system creates a collection of background dispatch queues, also named global queues. You can freely use them like you would do with custom queues, just keep in mind not to abuse the system by trying to use as many global queues as you can.

Using or not global queues, it’s almost out of the question the fact that you’ll need to access the main queue quite often; most probably to update the UI.
Global queue let’s you run tasks in the background. Once you are ready to update the UI, do so by using the main thread.

WorkItem

A DispatchWorkItem is a block of code that can be dispatched on any queue and therefore the contained code to be executed on a background, or the main thread. Think of it really simply; as a bunch of code that you just invoke, instead of writing the code blocks in the way we’ve seen in the previous parts.

Basically A workItem is a block of code that is executed by a queue. Right before execution it will notify via the notify method any other queues. In our example, we notify the main queue to run a block of code that simply prints out the value.

output:

–viewDidLoad–
button created
view hieararchy added button
–> useWorkItem()
create temp var ‘value’
DispatchWorkItem.perform()
—-executing DispatchWorkItem—–
value is has been changed to: 15
get global queue
execute DispatchWorkItem via async
DispatchWorkItem notify queue via main, print out value
<-- useWorkItem() workItem about to be executed!, its current value is: 15 ----executing DispatchWorkItem----- value is has been changed to: 20 ----executing DispatchWorkItem----- value is has been changed to: 25 ----executing DispatchWorkItem----- value is has been changed to: 30 ----executing DispatchWorkItem----- value is has been changed to: 35 ----executing DispatchWorkItem----- value is has been changed to: 40