Concurrent VS Non-Concurrent

Discussion in 'iOS Programming' started by daproject85, Nov 10, 2012.

  1. daproject85 macrumors member

    Joined:
    Apr 13, 2011
    #1
    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

    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 ?
     
  2. Guiyon, Nov 11, 2012
    Last edited: Nov 11, 2012

    Guiyon macrumors 6502a

    Joined:
    Mar 19, 2008
    Location:
    North Shore, MA
    #2
    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:@"http://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];
          }
      }
     
  3. daproject85 thread starter macrumors member

    Joined:
    Apr 13, 2011
    #3
    Guiyon, thanks for your reply... very detailed. I have some question. i have read this in the apple docs

    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??
     
  4. Guiyon, Nov 11, 2012
    Last edited: Nov 11, 2012

    Guiyon macrumors 6502a

    Joined:
    Mar 19, 2008
    Location:
    North Shore, MA
    #4
    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.
     
  5. daproject85 thread starter macrumors member

    Joined:
    Apr 13, 2011
    #5
    thanks Guiyon...so it looks like for MOST cases its better to use NSOperationqueue and using non-concurrent then
     
  6. Guiyon macrumors 6502a

    Joined:
    Mar 19, 2008
    Location:
    North Shore, MA
    #6
    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.
     

Share This Page