fabian789 fabian789 - 27 days ago 10
iOS Question

Cancel NSOperation in for loop?

I am trying to implement search on a background thread using

NSOperation
on
iOS
. I didn't want to subclass
NSOperation
so this is what I'm doing:

[searchQueue cancelAllOperations];
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self
elector:@selector(filterContentForSearchText:)
object:self.searchDisplayController.searchBar.text];
[searchQueue addOperation:op];
[op release];


The search method includes a for loop that checks whether what is being searched is in an array. Now when I cancel the
NSOperation
by calling
cancelAllOperations
, the for loop continues to run through the array. I would like to prevent this and was wondering whether it is legit to call this from within the for loop:

if ([[[searchQueue operations] objectAtIndex:0] isCancelled]) {
[tmp_array release]; // tmp_array is used to hold temporary results
[pool drain]; // pool is my autorelease pool
return;
}

Answer

One of the reasons to subclass NSOperation is to implement proper cancellation. You could do your approach, but it violates several good design principles. Basically, since cancellation requires the cooperation of the operation itself, NSInvocationOperation isn't built to cancel the invocation while it's already executing (though it can be successfully cancelled before it starts executing), as the running method shouldn't know anything about how it's called.

Instead, if you subclass NSOperation, you can put most of this functionality into the main method very easily:

@implementation MyOperation
- (void)main {
    if ([self isCancelled])
        return;

    for (...) {
        // do stuff

        if ([self isCancelled]) {
            [tmp_array release];
            return;
        }
    }
}

@end

Note also that you don't have to maintain your own autorelease pool with such an implementation.