问题
I am using a subclass of NSOperation to do some background processes. I want the operation to be cancelled when the user clicks a button.
Here's what my NSOperation subclass looks like
- (id)init{
self = [super init];
if(self){
//initialization code goes here
_isFinished = NO;
_isExecuting = NO;
}
return self;
}
- (void)start
{
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
return;
}
[self willChangeValueForKey:@"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:@"isExecuting"];
//operation goes here
}
- (void)finish{
//releasing objects here
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
- (void)cancel{
[self willChangeValueForKey:@"isCancelled"];
[self didChangeValueForKey:@"isCancelled"];
[self finish];
}
And this is how I am adding objects of this class to a queue and listening for KVO notifications
operationQueue = [[NSOperationQueue alloc] init]; [operationQueue setMaxConcurrentOperationCount:5]; [operationQueue addObserver:self forKeyPath:@"operations" options:0 context:&OperationsChangedContext];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == &OperationsChangedContext) {
NSLog(@"Queue size: %u", [[operationQueue operations] count]);
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
To cancel an operation (on a button click for instance), I tried calling -cancel but it doesn't make a difference. Also tried calling -finish but even that doesn't change anything.
Every time I add an operation to the queue, the queue size only increases. finish is called (checked using NSLog statements) but it doesn't really end the operation. I'm still not very confident I'm doing this right
Can someone please tell me where I am going wrong?
Thanks a lot
回答1:
From the NSOperation Class Reference:
Cancelling an operation does not immediately force it to stop what it is doing. Although respecting the value returned by the isCancelled is expected of all operations, your code must explicitly check the value returned by this method and abort as needed.
i.e. the cancel
method does not actually cancel the operation unless your implementation enforces this. Again, from the relevant section:
- (void)cancel
This method does not force your operation code to stop. Instead, it updates the object’s internal flags to reflect the change in state.
回答2:
You just need the following to achieve it:
In your NSOperation subclass, add to main method
while (! self.isCancelled) {
[NSThread sleepForTimeInterval:1];
}
In the GUI class, you need an instance variable to your NSOperation subclass, and in the method that manages the button, you cancel your NSOperation subclass. For instance:
- (IBAction) clickButton: (UIBarButtonItem *) item{
[myOperation cancel];
}
来源:https://stackoverflow.com/questions/1770529/iphone-return-from-an-nsoperation