Reputation: 3334
Basically, I would like to perform a cancel if the operation I'm adding to the queue does not respond after a certain timeout :
NSOperationQueue * queue = ...
[self.queue addOperationWithBlock:^{
// my block...
} timeoutInSeconds:5.0 hasTimedOutWithBlock:^{
// called after 5.0, operation should be canceled at the end
}];
Thanks Guys !
Upvotes: 5
Views: 5140
Reputation: 437382
You could do something like you asked for, but I might suggest adding a parameter to the first block by which the first block could check to see if the operation was canceled.
[queue addOperationWithBlock:^(NSOperation *operation) {
// do something slow and synchronous here,
// if this consists of a loop, check (and act upon) `[operation isCancelled]` periodically
} timeout:5.0 timeoutBlock:^{
// what else to do when the timeout occurred
}];
Maybe you don't need to check isCancelled
, but in some cases you would (generally the burden for responding to a cancellation rests on the operation itself), so that's probably a prudent parameter to add.
Anyway, if that's what you wanted, you might do something like the following:
@implementation NSOperationQueue (Timeout)
- (NSOperation *)addOperationWithBlock:(void (^)(NSOperation *operation))block timeout:(CGFloat)timeout timeoutBlock:(void (^)(void))timeoutBlock
{
NSBlockOperation *blockOperation = [[NSBlockOperation alloc] init]; // create operation
NSBlockOperation __weak *weakOperation = blockOperation; // prevent strong reference cycle
// add call to caller's provided block, passing it a reference to this `operation`
// so the caller can check to see if the operation was canceled (i.e. if it timed out)
[blockOperation addExecutionBlock:^{
block(weakOperation);
}];
// add the operation to this queue
[self addOperation:blockOperation];
// if unfinished after `timeout`, cancel it and call `timeoutBlock`
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// if still in existence, and unfinished, then cancel it and call `timeoutBlock`
if (weakOperation && ![weakOperation isFinished]) {
[weakOperation cancel];
if (timeoutBlock) {
timeoutBlock();
}
}
});
return blockOperation;
}
@end
Having provided that code sample, I must confess that there are a very narrow set of situations where something like the above might be useful. Generally it would be better addressed using another pattern. The vast majority of the time, when you want a cancelable operation, you would implement a NSOperation
subclass (often a concurrent NSOperation
subclass). See the Defining a Custom Operation Object section of the Operation Queues chapter of the Concurrency Programming Guide for more information.
Upvotes: 10