NSOperation and NSOperationQueue callback

I use the delegate pattern - that was the approach recommended to me by the guys at an Apple Developer Conference.

The scaffolding:

  1. Set up a protocol MyOperationDelegate with a setResult:(MyResultObject *) result method.
  2. Have whoever needs the result implement that protocol.
  3. Add @property id<MyOperationDelegate> delegate; to the NSOperation subclass you've created.

The work:

  1. When you create your operation, but before you queue it, tell it who should receive the result. Often, this is the object that creates the operation: [myOperation setDelegate: self];
  2. At the end of your operation's main function, call [delegate setResult: myResultObject]; to pass the result on.

Another alternative... if your need to do some work when the operation is complete, you could wrap that work up in a block and use a dependancy. This is very simple, especially with NSBlockOperation.

NSOperationQueue* myQueue = [[NSOperationQueue alloc] init];

NSBlockOperation* myOp = [NSBlockOperation blockOperationWithBlock:^{
    // Do work
}];

NSBlockOperation* myOp2 = [NSBlockOperation blockOperationWithBlock:^{
    // Do work
}];

// My Op2 will only start when myOp is complete
[myOp2 addDependency:myOp];

[myQueue addOperation:myOp];
[myQueue addOperation:myOp2];

Also you can use setCompletionBlock

[myOp setCompletionBlock:^{
    NSLog(@"MyOp completed");
}];

Add an observer to you class that listens for changes to the isFinished value of the NSOperation subclass

[operation addObserver:self
            forKeyPath:@"isFinished" 
               options:NSKeyValueObservingOptionNew
               context:SOME_CONTEXT];

Then implement the following method, having it look for the context your registered as your listener. You can make the data you want to retrieve from the NSOperation subclass available via an accessor method/property.

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context

Check out KVO Programming and Concurrency Programming.

Also, note that the observer will be received on the same thread as the Operation, so you may need to run code on the main thread if you want to deal with the UI.