Swift OperationQueue Handle Multi-Threading

Umair Ishrat Khan
5 min readDec 21, 2021

What is OperationQueue ?

There are two ways to handle multi-threading in IOS i.e:

  • GCD Dispatch
  • OperationQueue

But in both of them the popular one is GCD Dispatch because it’s easy to use can be done in 2 lines of code.

Then why did apple introduced OperationQueue are there any scenarios that GCD couldn’t handle??

What’s the difference between both?

Well consider GCD as GUI(Graphical User Interface) in OS which is very user friendly and used by many people.

Photo by Windows on Unsplash

And consider OperationQueue as CLI (Command Line interface) which is usually used by experts because it give you more control over the PC as compare to GUI.

What is an Operation. ?

Operation could be anything e.g downloading data from a URL or any other task that shouldn’t be perform on Main-thread if you are not familiar with Main-thread I highly recommend you reading my article on Threads & Concurrency before reading any further you can find that article here.

Since operation is an abstract class thats why you cannot use it directly for this reason you either subclass it or use one the system defined subclasses.

Practical Implementation of Operation:

As mention earlier operation it self is an abstract class hence we will be using system defined subclass i.e BlockOperation.

Operation in swift

In the above code we created a function inside struct named it ‘operations’ inside the function we created an instance of ‘BlockOperation’.

struct OperationExample {func operations(){// Create instance of operation sub-classlet operation = BlockOperation()

After this we added execution block these blocks will execute our required task.

struct OperationExample {func operations(){// Create instance of operation sub-classlet operation = BlockOperation()// Assign QOSoperation.qualityOfService = .utility// executing a taskoperation.addExecutionBlock {print("Task 1")}operation.addExecutionBlock {print("Task 2")}operation.addExecutionBlock {print("Task 3")}

At the end of the function we called the method .start() in order to start our operation.

struct OperationExample {func operations(){// Create instance of operation sub-classlet operation = BlockOperation()// Assign QOSoperation.qualityOfService = .utility// executing a taskoperation.addExecutionBlock {print("Task 1")}operation.addExecutionBlock {print("Task 2")}operation.addExecutionBlock {print("Task 3")}// Start executionoperation.start()}}

The print statement shows the following print “task 1”,“task 2”,“task 3”. This make us think that it is following fifo first in first out .

Well if you think its fifo then you are wrong Blockoperation start all the tasks at the same time regardless their order. And the task that gets completed first will be printed first.

Now we know what is operations lets move to the second segment OperationQueue.

What is OperationQueue?

Imagine you want to execute multiple operation together in that case you will create multiple BlockOpertions.

Then we will add these BlockOperation in one queue the queue that will execute these BlockOperation is called OperationQueue.

Let’s have a look at practical implementation:

As you can see we just added a few new lines to our code those lines are :

// Create a Queuelet queue = OperationQueue()// Now we will assign Quality of service to the queue and not the operationsqueue.qualityOfService = .utility// Add operations to queuequeue.addOperations([operation,operation2], waitUntilFinished: false)}

we created an instance of OperationQueue and assigned quality of service since we are working with operation queue we do not need to assign quality of service directly to operation blocks. Last we added the operations in the queue and the queue will now execute all the operations.

After all above a question might arise in your mind is OperationQueue ‘FIFO’ first in first out then the answer is NO!.

Ok so if OperationQueue doesn’t follow ‘fifo’ then what if I’ve 100 operations in queue won’t it suffocate the device??

In OperationQueue we have something called “MaxConcurrentOperationCount” that allows you to manually set the number of operations you want to execute concurrently. But apple has disliked this approach because OperationQueue is smart enough that by default it executes the Max. Concurrent Operations based on device hardware. So if you set it manually not every device is built equally and you might end up hanging your app on some devices. Thats why we should try to leave it as default.

Why Use Queue When We Have .start() ?

According to Apple Docs we shouldn’t execute the operation manuallay because:

Executing operations manually does put more of a burden on your code, because starting an operation that is not in the ready state triggers an exception.

But if you add the operation object in the queue the queue assumes all the responsibility for it.

Hence we should always use Queues and avoid manual execution.

If you liked my way of explanation and want me to write more articles kindly do follow me this really motivates me in writting more programming tutorials.

--

--

Umair Ishrat Khan

An energetic and motivated individual IOS developer/ Data Science Practitioner. Apart from computer science Martial arts interests me the most.