Choosing Between NSOperation and Grand Central Dispatch in iOS Swift 5 | Using Operations and OperationQueues in iOS Swift 5




Hello friends, In the previous article we were talking about What is the Concurrency how many ways to achieve Concurrency/Multithreading iOS and we have promised to come back with the second part. In the following we’re going to focus on OperationQueues and Choosing Between NSOperation and Grand Central Dispatch in iOS.

  • GCD is a low-level C API that permits developers to execute tasks concurrently. 
  • Operation queues, on the opposite hand, are high-level abstraction of the queue model and is made on top of GCD.
  • Day by day our applications need to do more and more complicated tasks without compromising their responsiveness. 
  • Unlike GCD, they don't conform to the First-In-First-Out order.
  • NSOperation allows to set dependencies on the operation.
  • NSOperation allows to cancel, resume, and restart the operation.
  • Imagine when some users, once they are tapping the button and therefore the button downloads some files or a picture. the download task shouldn't block the user interaction otherwise users kill the app or push to the background state. Things get complicated quickly when your application must do quite a couple of tasks. there's not much time to try to heavy add the most work cycle and still provide a responsive interface.

Operation:

Tasks submitted to the operation queue is in the form of NSOperation instance. We discussed in GCD that tasks are submitted in the block. The same can be done here but should be bundled inside the NSOperation instance. You can simply think of NSOperation as a single unit of work.

NSOperation is an abstract class so that you can't directly create instance of NSOperation.It has two subclasses.

  • NSBlockOperation
  • NSInvocationOperation

Operation class is an abstract class, you do not use it directly but instead subclass or use one of the system-defined subclasses (NSInvocationOperation or NSBlockOperation) to perform the actual task. Despite being abstract, the base implementation of Operation does include significant logic to coordinate the safe execution of your task. The presence of this built-in logic allows you to focus on the actual implementation of your task, rather than on the glue code needed to ensure it works correctly with other system objects. 

 

NSInvocationOperation:

Use this class to initiate an operation that consists of invoking a selector on a specified object.

An operation that manages the execution of a single encapsulated task specified as an invocation. The NSInvocationOperation class is a concrete subclass of NSOperation that you use to initiate an operation that consists of invoking a selector on a specified object. This class implements a non-concurrent operation.NSBlockOperation

In objective C we can create NSInvocationOperation while it’s not available in Swift. 
@implementation MyCustomClass
- (NSOperation*)taskWithData:(id)data {
    NSInvocationOperation* theOp = [[NSInvocationOperation alloc] initWithTarget:self
                    selector:@selector(myTaskMethod:) object:data];
 
   return theOp;
}
 
// This is the method that does the actual work of the task.
- (void)myTaskMethod:(id)data {
    // Perform the task.
}
@end 

developer.apple documentation
                           

NSBlockOperation:

Use this class to initiate operation with one or more blocks. The operation itself can contain more than one block and the operation will be considered as a finish when all blocks are executed.
The NSBlockOperation class is a concrete subclass of NSOperation that manages the concurrent execution of one or more blocks. You can use this object to execute several blocks at once without having to create separate operation objects for each. When executing more than one block, the operation itself is considered finished only when all blocks have finished executing.

// An instance of some Operation subclass
        let operation = BlockOperation {
            // perform task here
        }
        let queue = OperationQueue()
        queue.addOperation(operation)

Add Operations

Here two operations task and task1, added them into operation queue. Operation queue started both operation on some background thread and executed them.
func AddOperation()  {
            let queue = OperationQueue()
            let task = BlockOperation { [weak self] in
                self?.task1()
            }
            let task1 = BlockOperation { [weak self] in
                self?.task2()
            }
            queue.addOperation(task)
            queue.addOperation(task1)
        }
        func task1() {
            for i in 1...10{
                print("--------Task1----\(i)")
            }
        }
        func task2() {
            for i in 1...10{
                print("++++++++++Task2++++++++\(i)")
    //            when UI update use main queue
                //DispatchQueue.main.async{ [weak self] in
    //                self.lbldisplay.text = "\(i)"
                //}
            }
        }
++++++++++Task2++++++++1
++++++++++Task2++++++++2
++++++++++Task2++++++++3
++++++++++Task2++++++++4
++++++++++Task2++++++++5
++++++++++Task2++++++++6
++++++++++Task2++++++++7
++++++++++Task2++++++++8
++++++++++Task2++++++++9
++++++++++Task2++++++++10
--------Task1----1
--------Task1----2
--------Task1----3
--------Task1----4
--------Task1----5
--------Task1----6
--------Task1----7
--------Task1----8
--------Task1----9
--------Task1----10

GCD advantage over NSOperation:

  • For GCD implementation is very light-weight 
  • NSOperationQueue is complex and heavy-weight
  • GCD is very easy to use - if you want to do something in the background, all you need to do is write the code and dispatch it on a background queue. Doing the same thing with NSOperation is a lot of additional work.
  • Grand Central Dispatch is a low-level C API that interacts directly with Unix level of the system.NSOperation and NSOperationQueue are Objective-C classes.

NSOperation advantages over GCD:

i. Control On Operation-

Operations are often paused, resumed, and canceled. Once you dispatch a task using Grand Central Dispatch, you not have control or insight into the execution of that task. The NSOperation API is more flexible therein respect, giving the developer control over the operation's life cycle.

ii. Dependencies-

The completion block is called after the dependency operation starts, but it doesn't mean that the first operation didn't end. The operation will not be started until all of its dependencies return true for finished.

class myOperation1 : Operation {
    override func main() {
        print("op1 working....")
        for i in 1...10 {
            print("\(i)")
        }
    }
}

class myOperation2 : Operation {
    override func main() {
        print("op2 working....")
    }
}

let op1 = myOperation1()
let op2 = myOperation2()

op1.completionBlock = {
    print("op1 completed")
}

op2.completionBlock = {
    print("op2 completed")
}

op2.addDependency(op1)

let opsQue = OperationQueue()
opsQue.addOperations([op1, op2], waitUntilFinished: true)
Output-
op1 working....
1
2
3
4
5
6
7
8
9
10
op2 working....
op1 completed
op2 completed

iii. State of Operation-

A difference between GCD and NSOperation is that NSOperation has a simple description of its state of operation. Different states of operation are often in several states, counting on its current execution status.

Ready: It’s prepared to start out 
Executing: The task is currently running 
Finished: Once the method is completed Canceled: The task canceled

iv. Max Number of Operation

class myOperation1 : Operation {
    override func main() {
        print("op1 working....")
    }
}

class myOperation2 : Operation {
    override func main() {
        print("op2 working....")
    }
}

let op1 = myOperation1()
let op2 = myOperation2()

op1.completionBlock = {
    print("op1 finished")
}

op2.completionBlock = {
    print("op2 finished")
}

op2.addDependency(op1)

let opsQue = OperationQueue()
// setting maxConcurrentOperationCount to 1
opsQue.maxConcurrentOperationCount = 1
opsQue.addOperation(op1)
opsQue.addOperation(op2)

The NSOperationQueue also adds a variety of advantages to the combinationfor instanceyou'll specify the utmost number of queued operations which will run simultaneously. This makes it easy to regulate what percentage of operations run at an equivalent time or to make sequential operation queue.

When to Use NSOperation and Grand Central Dispatch:

GCD dispatch queues are better for short tasks that should have minimum performance and memory overhead. Everyone asks is when to use dispatch and operation queue my answer that is, it depends on the requirement to explain that let me give you an example, as you are seeing this video on youtube where you can pause, play or skip this video depends upon what you want so in this case I can say you have 100% control over the video however in the case of TV shows this is not possible. 

If you are watching a movie on TV then you cannot skip some songs or scenes similarly when you get such requirements where depending on the logical condition you should be able to cancel, pause or play a thread then the choice has to be NSOperationQueue or Operation queue because they have additional methods with help of which you can control your tasks for all the other cases.

You can use dispatch queue they don't have much drawbacks, operation queue probably gives better control over your thread you can set operational dependencies and many more usually.

The dispatch queue is just a single line of code so developers go ahead and use the dispatch queue and not the operational queue. so lets have a look at an example over here here I have an example of a dispatch queue you can see I can just add one line of code.



If you enjoyed this article please share.

Thanks for reading!!

Similar solutions you may also like...

Post a Comment

0 Comments