基本上,如果我添加到队列的操作在一定的超时后没有响应,我想执行取消:
NSOperationQueue * queue = ...
[self.queue addOperationWithBlock:^{
// my block...
} timeoutInSeconds:5.0 hasTimedOutWithBlock:^{
// called after 5.0, operation should be canceled at the end
}];
谢谢大家!
答案 0 :(得分:8)
您可以执行类似于您要求的操作,但我可能会建议在第一个块中添加一个参数,第一个块可以通过该参数检查该操作是否已取消。
[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
}];
也许你不需要检查isCancelled
,但在某些情况下你会(通常是取消取消的负担取决于操作本身),所以这可能是谨慎的要添加的参数。
无论如何,如果这是你想要的,你可能会做如下的事情:
@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
在提供了代码示例之后,我必须承认,存在一组非常狭窄的情况,其中上述内容可能有用。通常,使用其他模式可以更好地解决问题。绝大多数情况下,当您需要可取消操作时,您将实现NSOperation
子类(通常是并发NSOperation
子类)。有关详细信息,请参阅并发编程指南的Operation Queues章节中的定义自定义操作对象部分。