I've created a test project in which I'm testing my assumptions about NSOperation
and NSOperationQueue
before using them in my main project.
My code is pretty simple, so I'm going to include all of it here. This is using a command line Foundation project with ARC turned on.
Operation.h
#import <Foundation/Foundation.h>
@interface Operation : NSOperation
@property (readwrite, strong) NSString *label;
- (id)initWithLabel: (NSString *)label;
@end
Operation.m
#import "Operation.h"
@implementation Operation
- (void)main
{
NSLog( @"Operation %@", _label);
}
- (id)initWithLabel: (NSString *)label
{
if (( self = [super init] )) {
_label = label;
}
return self;
}
@end
Main.m
#import <Foundation/Foundation.h>
#import "Operation.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
id create = [[Operation alloc] initWithLabel: @"create"];
id update1 = [[Operation alloc] initWithLabel: @"update1"];
id update2 = [[Operation alloc] initWithLabel: @"update2"];
[update1 addDependency: create];
[update2 addDependency: create];
[queue addOperation: update1];
[queue addOperation: create];
[queue addOperation: update2];
[queue waitUntilAllOperationsAreFinished];
}
return 0;
}
My output looks like this:
2012-05-02 11:37:08.573 QueueTest[1574:1b03] Operation create
2012-05-02 11:37:08.584 QueueTest[1574:1903] Operation update2
2012-05-02 11:37:08.586 QueueTest[1574:1b03] Operation update1
Having written this and experimented with a few combinations, I found that when I reordered the queue setup like this:
[queue addOperation: update1];
[queue addOperation: create];
[queue addOperation: update2];
[update1 addDependency: create];
[update2 addDependency: create];
[queue waitUntilAllOperationsAreFinished];
I got the same output:
2012-05-02 11:38:23.965 QueueTest[1591:1b03] Operation create
2012-05-02 11:38:23.975 QueueTest[1591:1b03] Operation update1
2012-05-02 11:38:23.978 QueueTest[1591:1903] Operation update2
I should note that I have found in some runs that update2 is executed before update1, but that behaviour isn't surprising. Why should NSOperationQueue
be deterministic when I haven't asked it to be?
What I do find surprising is that somehow create is always executed before update1 and update2 even if everything is added to the queue before dependancies are added.
Obviously, this is a silly thing to do, but it's led me to wonder: Is the delay between when I add an operation to the queue and when it's executed documented, or in any way predictable? Exactly when does NSOperationQueue
start processing added operations?
Really, most importantly, exactly what is NSOperationQueue
waiting for and when will that wait bite me in some way I can't defend against?