1

Per Apple's documentation NSOperationQueue/NSOperation uses GCD under the hood. It provides functionality such as cancel, which is not available in GCD. Question: How does NSOperation implement cancel under the hood if GCD does not have mechanism this (or does it)?

Boon
  • 40,656
  • 60
  • 209
  • 315
  • 2
    It does not provide this ability directly and has to be built manually. Something like this looks about right: http://stackoverflow.com/questions/6737044/suspending-gcd-query-problem/6737719#6737719 – Dima May 30 '14 at 01:51

2 Answers2

3

According to NSOperationQueue Class Reference :

Queued operations are cancelled before they begin executing. If an operation is already executing, it is up to that operation to recognize the cancellation and stop what it is doing.

And NSOperation Class Reference :

Canceling 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. The default implementation of NSOperation does include checks for cancellation. For example, if you cancel an operation before its start method is called, the start method exits without starting the task.

Note: In OS X v10.6, the behavior of the cancel method varies depending on whether the operation is currently in an operation queue. For unqueued operations, this method marks the operation as finished immediately, generating the appropriate KVO notifications. For queued operations, it simply marks the operation as ready to execute and lets the queue call its start method, which subsequently exits and results in the clearing of the operation from the queue.

You should always support cancellation semantics in any custom code you write. In particular, your main task code should periodically check the value of the isCancelled method. If the method ever returns YES, your operation object should clean up and exit as quickly as possible.

As I understand, -[NSOperation cancel] only marks a flag, maybe isCancel. At the top of -[NSOperation start], it checks the flag and then exits if it is true.
By default, Apple only supports cancel an operation that isn't currently executing. If it is canceled while it's executing, the responsibility is in -[NSOperation main]code that the users implemented themselves.

With GCD, you can achieve that by wrapping blocks in a class that has an isCancel flag. At the first lines of the blocks, check the flag and exit if it's true.

@interface CancelableBlock : NSObject
@property (copy) dispatch_block_t block;
@property (assign) BOOL isCancel;

- (dispatch_block_t)wrappedBlock;
@end

@implementation CancelableBlock 
- (dispatch_block_t)wrappedBlock {
  return ^{ if (self.isCancel) return; self.block(); };
}
@end

When use it

dispatch_async(queue, [myblock wrappedBlock]);
3329
  • 1,411
  • 13
  • 17
0

Approximate answer: each NSOperation stores an is-canceled bit. When the operation begins execution, it checks the is-canceled bit before doing anything.

Greg Parker
  • 7,972
  • 2
  • 24
  • 21