Parallel Programming with Swift — Part 3/4

Operation and OperationQueue overview

Aaina jain
Swift India
4 min readDec 5, 2018

--

This article is part 3 of Parallel Programming with Swift Series. In Part 1, we looked into Dispatch Queue and system provided queues. In part 2 we focused on another way of defining tasks and powerful APIs provided by GCD. In this post let’s look into Operation API and flexibility it provides in comparison to Grand Central Dispatch.

If you want to have a look on all parts of series:

Concurrency & GCD — Parallel Programming with Swift — Part 1/4

GCD — Parallel Programming with Swift — Part 2/4

Operations and Operation Queue Overview — Parallel Programming with Swift — Part 3/4

Operations:

Operation is an Object oriented way to encapsulate work that needs to be performed asynchronously.

Operation represents a single unit of work. It’s an abstract class that offers a useful, thread-safe structure for modeling state, priority, dependencies and management.

— NSHipster

As operation is an abstract class, you don’t use it directly. Foundation provides two system-defined sub classes InvocationOperation and BlockOperation to execute task. As being said with defined sub classes you just have to focus on the actual implementation of your task.

An operation executes task once and can’t be used to execute it again. You execute operations by adding them to an operation queue. An operation queue executes its operations either directly, by running them on secondary threads, or indirectly using the libdispatch library (i.e. Grand Central Dispatch). Thus Operation API is a higher level abstraction of Grand Central Dispatch.

You may be wondering: What’s task? 🤔

Let’s discuss these terms:

  • Task: A single piece of work that needs to be done.
  • Process: An executable chunk of code, which can be made up of multiple threads. Processes are the instances of your app. Whenever you perform cold launch of app, Process ID get change while it remain same when you perform hot launch. It contains everything needed to execute your app, this includes your stack, heap, and all other resources.
  • Thread: A mechanism provided by the operating system that allows multiple sets of instructions to operate at the same time within a single application. Compared to processes, threads share their memory with their parent process. This can result in problems, such as having two threads changing a resource (e.g. a variable) at the same time. Threads are a limited resource on iOS. It’s limited to 64 threads at the same time for one process while it’s not mentioned officially in any document as it varies based on context and number of cores.

Operation can be executed directly by calling a start() method. But it comes with it’s own overhead. 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. The isReady property reports on the operation’s readiness.

Since Operations are classes, we can use them to encapsulate our business logic.

Examples of tasks that can use Operation include network requests, image resizing, text processing, performing prefetching in background fetch or any other long-running task that produces associated state or data. It can be use to implement login sequence of application as well. An operation can have dependencies to other operations and that is a powerful feature Grand Central Dispatch lacks. If there is need to perform several tasks in a specific order, then operations are a good solution.

Operation Life Cycle:

Operation States:

Operation objects maintain states internally to determine when it is safe to execute and also to notify external clients of the progress through the operation’s life cycle.

isReady: It informs client when an operation is ready to execute. This keypath returns true when the operation is ready to execute now or false if there are still unfinished operations on which it is dependent.

isExecuting: This keypath tells us whether the operation is actively working on its assigned task. isExecuting returns true if the operation is working on its task or false if it is not.

isFinished: It informs that an operation finished its task successfully or was cancelled. An operation object does not clear a dependency until the value at the isFinished key path changes to true. Similarly, an operation queue does not dequeue an operation until the isFinished property contains the value true

isCancelled: The isCancelled key path inform clients that the cancellation of an operation was requested.

If you cancel an operation before its start() method is called, the start() method exits without starting the task.

OperationQueue:

An operation queue executes its queued Operation objects based on their priority and readiness in FIFO order. After being added to an operation queue, an operation remains in its queue until it is finished with its task. An operation can’t be removed directly from a queue after it has been added.

Operation queues retain operations until they’re finished, and queues themselves are retained until all operations are finished. Suspending an operation queue with operations that aren’t finished can result in a memory leak.

Operations within a queue are organized according to their readiness i.e. (isReady property returns true), priority level & dependencies, and are executed accordingly. If all of the queued operations have the same queuePriority and are ready to execute when they are put in the queue, they’re executed in the order in which they were submitted to the queue. Otherwise, the operation queue always executes the one with the highest priority relative to the other ready operations.

An operation object is not considered ready to execute until all of its dependent operations have finished executing.

Thanks for reading article.

You can catch me at:

Linkedin: Aaina Jain

Twitter: __aainajain

--

--