title: Serializing asynchronous tasks in objective C
body: <p>I wanted to be able to serialize 'genuinely' async methods, for example:</p>
  
  <ul>
  <li>making a web request</li>
  <li>showing a UIAlertView</li>
  </ul>
  
  <p>This is typically a tricky business and most samples of serial queues show a 'sleep' in an NSBlockOperation's block. This doesn't work, because the operation is only complete when the callback happens. </p>
  
  <p>I've had a go at implementing this by subclassing NSOperation, here's the most interesting bits of the implementation:                      </p>
  
  <pre><code>+ (MYOperation *)operationWithBlock:(CompleteBlock)block
  {
      MYOperation *operation = [[MYOperation alloc] init];
      operation.block = block;
      return operation;
  }
  
  - (void)start
  {
      [self willChangeValueForKey:@"isExecuting"];
      self.executing = YES;
      [self didChangeValueForKey:@"isExecuting"];
      if (self.block) {
          self.block(self);
      }
  }
  
  - (void)finish
  {
      [self willChangeValueForKey:@"isExecuting"];
      [self willChangeValueForKey:@"isFinished"];
      self.executing = NO;
      self.finished = YES;
      [self didChangeValueForKey:@"isExecuting"];
      [self didChangeValueForKey:@"isFinished"];
  }
  
  - (BOOL)isFinished
  {
      return self.finished;
  }
  
  - (BOOL) isExecuting
  {
      return self.executing;
  }
  </code></pre>
  
  <p>This works well, here's a demonstration...</p>
  
  <pre><code>NSOperationQueue *q = [[NSOperationQueue alloc] init];
  q.maxConcurrentOperationCount = 1;
  
  dispatch_queue_t queue = dispatch_queue_create("1", NULL);
  dispatch_queue_t queue2 = dispatch_queue_create("2", NULL);
  
  MYOperation *op = [MYOperation operationWithBlock:^(MYOperation *o) {
      NSLog(@"1...");
      dispatch_async(queue, ^{
          [NSThread sleepForTimeInterval:2];
          NSLog(@"1");
          [o finish]; // this signals we're done
      });
  }];
  
  MYOperation *op2 = [MYOperation operationWithBlock:^(MYOperation *o) {
      NSLog(@"2...");
      dispatch_async(queue2, ^{
          [NSThread sleepForTimeInterval:2];
          NSLog(@"2");
          [o finish]; // this signals we're done
      });
  }];
  
  [q addOperations:@[op, op2] waitUntilFinished:YES];
  
  [NSThread sleepForTimeInterval:5];
  </code></pre>
  
  <p>Note, I also used a sleep but made sure these were executing in background thread to simulate a network call. The log reads as follows</p>
  
  <pre><code>1...
  1
  2...
  2
  </code></pre>
  
  <p>Which is as desired. What is wrong with this approach? Are there any caveats I should be aware of?</p>