Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

daproject85

macrumors member
Original poster
Apr 13, 2011
37
0
hi Forum,

I am starting to dive into NSOperation and NSOperationQueue...and my brain is on overload right now... there are so many different options to use when using threads in iOS. But I have read the concurrent VS non-concurrent article in apple docs and for the life of me I dont get...please help... i honestly dont even know where to start but it says

If you plan on executing an operation object manually, instead of adding it to a queue, you can design your operation to execute in a concurrent or non-concurrent manner. Operation objects are non-concurrent by default. In a non-concurrent operation, the operation’s task is performed synchronously—that is, the operation object does not create a separate thread on which to run the task. Thus, when you call the start method of a non-concurrent operation directly from your code, the operation executes immediately in the current thread. By the time the start method of such an object returns control to the caller, the task itself is complete.

In contrast to a non-concurrent operation, which runs synchronously, a concurrent operation runs asynchronously. In other words, when you call the start method of a concurrent operation, that method could return before the corresponding task is completed. This might happen because the operation object created a new thread to execute the task or because the operation called an asynchronous function. It does not actually matter if the operation is ongoing when control returns to the caller, only that it could be ongoing.

my question is

Why would someone even use NSOperation for a non-concurrent op (synchronously)?? isnt the whole point of using NSOperation to use it to execute an OP in a new thread other than main ?
 
When Apple uses concurrent vs non-concurrent in this context, they mean 'does the start method return immediately'. For example, take the following to 'start' implementations:

  • Concurrent Operation
    When this start method returns, the operation won't be complete yet. Since NSOperation can't depend on this method returning as a signal that the job is complete, you now need to handle telling the operation's queue if it's executing, finished, etc. by sending KVO willChangeValueForKey: and didChangeValueForKey: notifications for the "isExecuting" and "isFinished" keypaths. This means you need to do a bit more work in order to get the operation up, running and managing its state, but you have a lot more control.
    Code:
    - (void)start
    {
        void (^completionHandler)(NSURLResponse*, NSData*, NSError*) = ^(NSURLResponse *response, NSData *data, NSError *error) {
            if (error)
            {
                NSLog(@"request failed: %@", error);
            }
            else
            {
                NSLog(@"request read '%lu' bytes", (unsigned long)[data length]);
            }
    
            [self willChangeValueForKey:@"isExecuting"];
            [self setValue:[NSNumber numberWithBool:NO]
                forKey:@"isExecuting"];
            [self didChangeValueForKey:@"isExecuting"];
    
            [self willChangeValueForKey:@"isFinished"];
            [self setValue:[NSNumber numberWithBool:YES]
                forKey:@"isFinished"];
            [self didChangeValueForKey:@"isFinished"];
        };
    
        [self willChangeValueForKey:@"isExecuting"];
        [self setValue:[NSNumber numberWithBool:YES]
            forKey:@"isExecuting"];
        [self didChangeValueForKey:@"isExecuting"];
        
        [self willChangeValueForKey:@"isFinished"];
        [self setValue:[NSNumber numberWithBool:NO]
            forKey:@"isFinished"];
        [self didChangeValueForKey:@"isFinished"];
    
        NSURL *opURL = [NSURL URLWithString:@"https://forums.macrumors.com"];
    
        // Start an asynchronous URL request and fire it off into the background. This method will
        // return immediately but the operation will run and the 'completionHandler' will be
        // called once the request is completed.
        [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:opURL]
                                           queue:[NSOperationQueue currentQueue]
                               completionHandler:completionHandler];
    }
  • Non-concurrent Operation
    Here, the start method returns as soon as the job is complete. Since there's no long running, background operations NSOperation can assume that once the start method returns, all the work is done and the operation is completed. This makes implementation of the operation much easier but it can be limiting, especially when working with asynchronous APIs.
    Code:
    - (void)main
    {
        for (int i = 0; i < 30; ++i)
        {
            [self doSomeLongRunningOperation];
        }
    }
 
Last edited:
Guiyon, thanks for your reply... very detailed. I have some question. i have read this in the apple docs

If you want to do a concurrent operation then you must override these methods:

start
isConcurrent
isExecuting
isFinished

If you are doing non-concurrent operations then all you must override is the following method:

main

you mentioned below that you override start and it makes it a concurrent operation, so it runs parrellel to the main thread. But your second "non-concurrent" example (which means it doesnt not run in parallel to the main thread???) also has start overridden. That really confused me...

or did i get it completely wrong, regardless whether its concurrent or non-concurrent the process runs in a seperate thread?

my other question is: is it true that if you use NSOperationqueue with NSOperation i wouldn't have to worry about all that??
 
you mentioned below that you override start and it makes it a concurrent operation, so it runs parrellel to the main thread. But your second "non-concurrent" example (which means it doesnt not run in parallel to the main thread???) also has start overridden. That really confused me...

First of all, I made a mistake in the code, the non-concurrent operation should override - [NSOperation main], not - [NSOperation start]. In this case, don't worry about whether you are on the main thread or not; if you are using an NSOperationQueue it will automatically handle all the bits of setting up a separate queue and dispatching the operations you add. The concurrent vs non-concurrent relates solely to how you are managing the lifecycle of the NSOperation. A non-concurrent operation has the following lifecycle:
  1. [_myOperationQueue addOperation:myNonconcurrentOperation]
  2. - [NSOperation start]
  3. - [MyNonconcurrentOperation main]
  4. operation completed!

In a non-concurrent operation, the important thing to realize is that the start (and the main you implement) method block until the operation is completed, however long that takes. It doesn't matter what thread the operation is on, the important part is that as soon as your main method returns, the operation is done and removed from the queue; NSOperation handles the lifecycle tracking, setting isExecuting, isFinished, etc.


A concurrent operation has the following lifecycle:
  1. [_myOperationQueue addOperation:myNonconcurrentOperation]
  2. - [MyNonconcurrentOperation start] // Sets up and starts the operation
  3. Doing things for my operation. i.e.: waiting for NSURLConnection delegate callbacks, etc
  4. finished the operation so fire off the isExecuting and isFinished KVO notifications
  5. operation completed!
In a concurrent operation, you (or, the developer) handles tracking the lifecycle of an operation and notifying the NSOperation of what state it should be in. This means that the NSOperation it not considered complete when the start method returns; it is only complete once isFinished is set to 'YES' and the proper KVO notifications are sent.
 
Last edited:
thanks Guiyon...so it looks like for MOST cases its better to use NSOperationqueue and using non-concurrent then
 
thanks Guiyon...so it looks like for MOST cases its better to use NSOperationqueue and using non-concurrent then

To a large degree, it really depends on what type of operations you are trying to wrap. Take scaling and rotating a UIImage; You *can* implement it as a concurrent operation, but it would be much easier to implement as a non-concurrent NSOperation (it's a synchronous, processor intensive operation). However, if you need to use something like NSXMLParser, a non-concurrent operation would be messy and difficult compared to a concurrent implementation because of the asynchronous delegation API.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.