Well, as I understand it, you have two questions:
Do you need the performSelectorOnMainThread: segment that appears in the comments of your code? What does this code do?
Why _isCancelled n't the _isCancelled flag change when cancelAllOperations called in the NSOperationQueue that contains this operation?
Let's handle it. I assume your subclass of NSOperation is called MyOperation , just for the convenience of explanation. I will explain what you misunderstand, and then give a corrected example.
1. Concurrent NSOperations
In most cases, you will use NSOperation with NSOperationQueue , and from your code, it looks like what you are doing. In this case, your MyOperation will always run in the background thread, regardless of what the -(BOOL)isConcurrent method returns, since NSOperationQueue explicitly designed to perform operations in the background.
As a rule, you do not need to override the method -[NSOperation start] , because by default it just calls the -main method. This is a method that you must override. By default, the -start method already processes the isExecuting and isFinished for you at appropriate times.
So, if you want NSOperation run in the background, just override the -main method and place it on the NSOperationQueue .
performSelectorOnMainThread: in your code will cause each instance of MyOperation always perform its task in the main thread. Since only one piece of code can run downstream at a time, this means that no other MyOperation can be started. The goal of NSOperation and NSOperationQueue is to do something in the background.
The only time you want to force things into the main thread is when you update the user interface. If you need to update the interface when MyOperation ends, that is, when you should use performSelectorOnMainThread: I will show how to do this in my example below.
2. Cancel NSOperation
-[NSOperationQueue cancelAllOperations] calls the method -[NSOperation cancel] , which calls subsequent calls -[NSOperation isCancelled] to return YES . However , you did two things to make it ineffective.
You use @synthesize isCancelled to override the NSOperation -isCancelled method. There is no reason for this. NSOperation already implements -isCancelled perfectly acceptable way.
You check your own _isCancelled instance variable to determine if the operation has been canceled. NSOperation ensures that [self isCancelled] will return YES if the operation was canceled. It does not guarantee that your custom setter method will be called, or that your own instance variable has been updated. You must check [self isCancelled]
What should you do
Title:
// MyOperation.h @interface MyOperation : NSOperation { } @end
And implementation:
// MyOperation.m @implementation MyOperation - (void)main { if ([self isCancelled]) { NSLog(@"** operation cancelled **"); } // Do some work here NSLog(@"Working... working....") if ([self isCancelled]) { NSLog(@"** operation cancelled **"); } // Do any clean-up work here... // If you need to update some UI when the operation is complete, do this: [self performSelectorOnMainThread:@selector(updateButton) withObject:nil waitUntilDone:NO]; NSLog(@"Operation finished"); } - (void)updateButton { // Update the button here } @end
Note that you do not need to do anything with isExecuting , isCancelled or isFinished . All of them are processed automatically for you. Just override the -main method. It is easy.
(Note: technically, this is not a “parallel” NSOperation , in the sense that -[MyOperation isConcurrent] will return NO , as implemented above, but will be executed in the background thread. isConcurrent really needs to be called -willCreateOwnThread , as this is a more accurate description of the intent of the method .)