GCD does not have built-in support for cancellation; if it is important to be able to cancel background tasks, then checking the flag, as you showed, is an acceptable solution. However, you can appreciate how quickly cancellation requires an answer; if some of these method calls are quite short, you can get away with checking less often.
You asked if you can use NSOperation flags to support undo. The answer is no. GCD is not based on NSOperation. In fact, in Snow Leopard, NSOperation and NSOperationQueue were reimplemented for internal GCD use. So addiction is the other way around. NSOperation is a higher-level design than GCD. However, even if you use NSOperation, your cancellation implementation will be basically the same; you still have to periodically check self.isCancelled to see if you should abandon the spacecraft design.
The only concern I have when implementing the CHECKER macro is that it implements an unexpected return . Therefore, you must be careful with memory leaks. If you configured your own NSAutoreleasePool in a background thread, you need to drain it before returning. If you specified alloc ed or retain any objects, you may need to release them before returning.
Since all this cleanup must be performed on every check, you may want to go to one return point. One way to do this is to wrap each call of your method in an if (pleaseAbandonYourEfforts == NO) { } block. This will allow you to quickly go to the end of the method after the cancellation was requested, and save the cleanup in one place. Another option, although some may not like this, would be to make the call to use the goto cleanup; macro goto cleanup; and define the label cleanup: at the end of the method in which you release everything that should be released. Some people don't like using goto almost religious way, but I found that an advanced switch to a cleaning shortcut like this is often a cleaner solution than alternatives. If you do not like this, then all this is done in the if block.
Edit
I feel the need for further clarification of my previous statement on the existence of a single point of return. With the CHECKER macro, as defined above, the -buildGuts method can return at any point where this macro is used. If there are any stored objects in this method, they must be cleaned before returning. For example, imagine this very reasonable change for your -buildGuts method:
-(void)buildGuts { // we are actually in the BG here... NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; CHECKER [self blah blah]; CHECKER [self blah blah]; CHECKER [self recordSerialNumberUsingFormatter:formatter]; // ... etc ... [formatter release]; return; }
Please note that in this case, if the CHECKER macro forces us to return to the end of the method, then the object in formatter will not be released and will be skipped . Although the call [self quickly wrap up in a bow] can handle cleanup for any objects accessible through an instance variable or through a global pointer, it cannot release objects accessible only locally in the buildGuts method. This is why I proposed a goto cleanup implementation that would look like this:
#define CHECKER if ( pleaseAbandonYourEfforts == YES ) { goto cleanup; } -(void)buildGuts {
Within this implementation, the formatter will always be released, regardless of when the cancellation occurs.
In short, whenever you create a macro that can make you return from a method, you must be sure that before you return prematurely, all memory management is taken care of. It is difficult to do this with a macro that causes a return.