To answer your questions:
- It's safe to combine this particular sequence of operations with the dependencies you have given with
maxConcurrentOperations = 1
.
- The queue will run
op2
, op3
and op1
or op2
, op1
, op3
if you reverse the dependency order of op1
and op2
.
Theres nothing tricky in the dependency chain you've specified and NSOperationQueue
can take care of things automatically. You can only really get into trouble if you specify a circular dependency (e.g op3
depends on op1
), or you have an operation that isn't added to the queue, and so can't get executed to satisfy a dependency.
Apple has this to say about cancellation in the NSOperationQueue class reference:
Canceling an operation causes the operation to ignore any dependencies it may have. This behavior makes it possible for the queue to execute the operation’s start method as soon as possible. The start method, in turn, moves the operation to the finished state so that it can be removed from the queue.
All NSOperation subclasses should handle cancellation correctly by first checking to see if it has been cancelled and then immediately finish the operation without performing any actions. If this isn't done then it's a bug, and operations may execute even though they have been cancelled.
(Interestingly this also applies for NSBlockOperation, which I didn't realise. You explicitly need to check self.isCancelled
in the block).
I used CodeRunner on the App Store to try this all out and modified your program slightly. It's reproduced below.
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
@autoreleasepool {
NSOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"op1"); }];
NSOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"op2"); }];
NSOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"op3"); }];
[op3 addDependency:op2];
[op2 addDependency:op1];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
[queue addOperations:@[op1, op2, op3] waitUntilFinished:YES];
}
}
For a NSBlockOperation
to refer to itself you need to do this, which is a bit disgusting but looks better in a NSOperation
subclass as you can refer to self
.
__block NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"op1 cancelled=%d", op1.cancelled); }];