Search code examples
iphoneobjective-ccocoacocoa-touchnsoperationqueue

Cancelling NSOperationQueue from within NSOperation


I have some iPhone SDK 4.0 code which initializes an NSOperationQueue and then adds three classes (ClassA, ClassB, and ClassC) to run one after the other. ClassA, ClassB, and ClassC are all sub-classes of NSOperation.

The relevant code is included below.

ClassA *classA = [[ClassA alloc] init];
ClassB *classB = [[ClassB alloc] init];
ClassC *classC = [[ClassC alloc] init];

[classB addDependency:classA];
[classC addDependency:classB];

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

[queue addOperation:classA];
[queue addOperation:classB];
[queue addOperation:classC];

[classA release];
[classB release];
[classC release];
[queue release];

The reason for the dependencies is because classB should only run if classA completes its operation successfully. Likewise, classC should only run if classB completes successfully.

At the moment I am having difficulty figuring out how to prevent, for example, classB from running if classA does not complete successfully. Continuing with this example, I was thinking of somehow evoking [NSOperationQueue cancelAllOperations] from within classA but I don't know how to get a handle on the parent NSOperationQueue from within classA (which is an NSOperation sub-class). This was just my initial thought, so I would be open to any other better suggestions for achieving the same outcome!

There is conditional code within each of the classes to determine whether they have completed properly - at the moment they are just NSLogging "Success" or "Fail" to the Console for debugging purposes. In a perfect world I would just like to be able to replace the NSLog(@"Fail") statement in each class with some code which will stop all of the other classes in the NSOperationQueue from running.

Any suggestions would be most welcome (and appreciated).


Solution

  • You could set a property in classA :

    @property (readonly) BOOL completedSucessfully;
    

    and set this to YES at the end of classA's main method.

    Then, just check it at the start of classB.

    - (void)main {
        if (NO == [[dependencies objectAtIndex:0] completedSucessfully])
            return;
    

    Now, classB will just stop if classA reports failure.

    NB You will probably need more error checking that in the example above i.e. making sure that you have dependencies, checking that it's the correct class etc.

    - (void)main {
        for (id *temp in [self dependencies])
            if ([temp isKindOfClass:[ClassA class]])
                if (NO == [(ClassA *)temp finishedSucessfully])
                    return;