I just dealt with this problem myself. I could not understand why when I cancelled my NSOperation
subclass, it was never removed from the NSOperationQueue
. It turns out that my overridden isReady
method was to blame. The isReady
method was checking the super implementation AND whether a property had been set, which it hadn't, which is why the operation was getting cancelled. However, apparently if an NSOperation
instance never reaches the ready state, even if it is cancelled, the NSOperationQueue
will not remove that operation until is has reached the ready state. Hence, the solution is to OR your custom conditions for readiness with the isCancelled
property value. Alternatively, you can change the logic such that the operation will always be ready, but do nothing in the main method if your conditions for readiness are not met, depending on your application logic.
Example:
// for proper KVO compliance
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
NSSet *keys = [super keyPathsForValuesAffectingValueForKey:key];
NSString *readyKey = NSStringFromSelector(@selector(isReady));
if ([readyKey isEqualToString:key]) {
keys = [keys setByAddingObjectsFromArray:@[NSStringFromSelector(@selector(url)), NSStringFromSelector(@selector(isCancelled))]];
}
return keys;
}
- (BOOL)isReady
{
return (this.url != nil || this.isCancelled) && super.isReady;
}
- (void)setUrl:(NSURL *)url
{
if (self.url == url) {
return;
}
NSString *urlKey = NSStringFromSelector(@selector(url));
[self willChangeValueForKey:urlKey];
_url = url;
[self didChangeValueForKey:urlKey];
}
Thanks to NSHipster's KVO article for the above KVO-related code.
b
depends ona
,b
will be execute aftera.finished == true
andb.ready == true
– nRewikcancel
do you calloperationQueue.cancelAllOperations()
ora.cancel()
? – nRewika
is cancelled or not. You should setoperation.finished==true
at the final state to makeNSOperationQueue
removes theoperation
. You should set.ready==true
whenever it's ready to begin theoperation
. In life cycle ofoperation
, you should frequently check.cancelled
whenever.cancelled == true
, you should stopoperation
and set.finished == true
. – nRewik