Hello ladies and gentlemen, Leo here. Today we’ll explore OperationQueue in Swift in Swift.
We will learn how it can help you improve your async operations. The scope is introductory therefore we won’t going to explore every possibility with OperationQueues, the focus is the basics of the API.
The main goal to achieve is how to build asynchronous dependency graphs in Swift, for example, imagine you have an asynchronous operation that could be only run after two other asynchronous operations are done, you can achieve this with OperationQueue.
Let’s go!
OperationQueue in Swift
What is an OperationQueue? As you can see here in the OperationQueue class docs, an OperationQueue is :
A queue that regulates the execution of operations.
But wait a minute, what is an Operation?
Again, in the Operation class docs:
An abstract class that represents the code and data associated with a single task.
So you have a queue and the operations that you will add to it. You can do synchronous and asynchronous tasks on the queue, today we’ll just look at the async ones.
The Problem – Solved using OperationQueue in Swift
Imagine that you have some async processing that when it finishes trigger other async processes and so on.
Before we attack the problem let’s check the code below:
let operation1 = BlockOperation { //1 for x in 0...5 { print(x) } } let operation2 = BlockOperation { //1 for x in 11...15 { print(x) } } let operation3 = BlockOperation { //1 for x in 21...25 { print(x) } } let operationQueue = OperationQueue() //2 operationQueue.addOperations([operation1,operation2,operation3], waitUntilFinished: false) //3
The (1) mark is one way to create the Operation class we discuss above, those are only computing numbers but you can insert and even create your own Custom Operation classes (it’s not the scope of this post, but maybe in the future). By default, the OperationBlock isn’t asynchronous on its own so we’ll have to put it in OperationQueue to process asynchronously as we are doing in the (3) mark. The (2) only create an OperationQueue.
One more thing: did you notice that we have a waitUntilFinished equals false when adding Operations? This will not block our thread making the program continue while the operations are running. You can set it to true if you want a blocking operation.
Let’s run and see the result:
And every time you run this will be a different result. But now it’s when the magic happens, what if I wanted to have a little more control over this execution? Now it’s when the Operation and OperationQueue rise and shine, the API provide us the right tools to achieve that.
Asynchronous Dependency Graph using OperationQueue in Swift
In the same example, you can add some Operation dependencies, this way, build an asynchronous dependency graph. Check the code below:
let operation1 = BlockOperation { for x in 0...5 { print(x) } } let operation2 = BlockOperation { for x in 11...15 { print(x) } } operation2.addDependency(operation1) // 1 let operation3 = BlockOperation { for x in 21...25 { print(x) } } operation3.addDependency(operation1) // 1 let operationQueue = OperationQueue() operationQueue.addOperations([operation1,operation2,operation3], waitUntilFinished: false)
Check the (1) marks in the code. We are creating a dependency here saying to the queue: Hey Queue, you will only run operations 2 and 3 WHEN operation 1 is finished, because they are dependent on the first one.
And the result is:
You can see that first, the queue completes all the operation1 processing to after that asynchronous run the other 2 operations in it.
Did you notice that you can even implement your own DispatchGroup with OperationQueue? Simply put one Operation that depends on every other Operation in the queue and it’s done!
OperationQueue properties
There are two interesting things to notice in the Operation class, the qualityOfService and queuePriority properties.
The qualityOfService properties affect the priority with which an operation object is given access to system resources such as CPU time, network resources, disk resources, and so on.
And the queuePriority contains the relative priority of the operation. This value is used to influence the order in which operations are dequeued and executed. Priority values should not be used to implement dependency management among different operation objects. You can use addDependecy() method to do that.
Tweaking OperationQueues
The final thoughts about this introduction to OperationQueues are some properties you can use to control the async execution of your code.
The maxConcurrentOperationCount property of the queue can give you control on guess what? How many concurrent operations you can have each time. So imagine that you have 3 items in the queue like the example above, if you set this property to 2, they will run two random operations at a time, and only when one of the finishes it works it will initiate the third one.
let operation1 = BlockOperation { for x in 0...6 { print(x) } } let operation2 = BlockOperation { for x in 11...15 { print(x) } } let operation3 = BlockOperation { for x in 21...25 { print(x) } } let operationQueue = OperationQueue() operationQueue.maxConcurrentOperationCount = 2 // this property operationQueue.addOperations([operation1,operation2,operation3], waitUntilFinished: false)
Resulting in:
As you can see, operation3 only started after the completion of operation.
Summary
This brief introductory article shows that an OperationQueue gives you the power to easily create asynchronous dependency graph operations and it’s a very versatile tool to have in your Swift toolbox.
Of course, you can achieve the same results using pure GCD functions because OperationQueue is only a wrapper of it with some KVO and KVC magic in it. You can even get the dispatchQueue from OperationQueue using underlyingQueue property if you want to.
That’s all my people, I hope you liked reading this article as much as I enjoyed writing it. If you want to support this blog you can Buy Me a Coffee or leave a comment saying hello. You can also sponsor posts and I’m open to freelance writing!
You can reach me on LinkedIn or Twitter and send me an e-mail through the contact page.
Thanks for the reading and… That’s all folks.
Credits – image