NSOperationQueue:在超时给定后取消操作

时间:2014-08-24 18:09:36

标签: ios objective-c asynchronous nsoperation nsoperationqueue

基本上,如果我添加到队列的操作在一定的超时后没有响应,我想执行取消:

NSOperationQueue *   queue = ...

[self.queue addOperationWithBlock:^{
        // my block...
    } timeoutInSeconds:5.0 hasTimedOutWithBlock:^{
        // called after 5.0, operation should be canceled at the end
}];

谢谢大家!

1 个答案:

答案 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章节中的定义自定义操作对象部分。