【问题标题】:NSOperationQueue : cancel an operation after a timeout givenNSOperationQueue : 给定超时后取消操作
【发布时间】:2014-08-24 18:09:35
【问题描述】:

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

NSOperationQueue *   queue = ...

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

谢谢各位!

【问题讨论】:

  • NSOperation 类参考将是一个很好的起点。
  • 你在那个初始块中做什么?很少有情况不能用另一种模式更好地解决这个问题,但我们很难在不知道您正在尝试做什么的情况下提供建议。

标签: ios objective-c asynchronous nsoperation nsoperationqueue


【解决方案1】:

您可以按照您的要求执行操作,但我可能建议在第一个块中添加一个参数,第一个块可以通过该参数检查操作是否被取消。

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

【讨论】:

  • 嗨 Rob,我想用它来与 BLE 设备通信...我想用自定义超时处理我的每个命令...它是否属于你的那个非常狭窄的集合您正在考虑的情况?
  • 基本上,我发现这对网络通信很有用......而且我认为 AFNetworking 有这种模式
  • 不,AFNetworking 是我在最后一段中提到的模式的一个很好的例子,您不使用上述模式,而是创建一个并发的NSOperation 子类。在 AFNetworking 的情况下,它依靠NSURLConnection 来处理超时并在发生这种情况时完成操作。而且,除此之外,与上面不同的是,这意味着超时逻辑与网络请求的开始相关,而不是与操作的调度(如果它是串行队列或具有其他依赖关系,可能从某个未来时间)。
  • @NicolasHenin 在回答您的问题时,addOperationWithBlock 的超时再现是否对 BLE 应用程序有意义,如果确实如此,我会感到惊讶,因为 BLE 请求是异步发生的,并且上面假设第一个块是同步运行的。如果您使用NSOperationQueue 方法,并发NSOperation 可能会更好地处理异步请求。但鉴于 CBCentralManager 代表处于经理级别(而不是请求级别),我不确定 NSOperationQueue 是否完全适合 BLE。
  • 我正在使用 LGBluetooth 一个高于 Core Bluetooth 的包装器,它提供了一个带有 Blocks 的 API,但是你是对的,或者 CBCentralManager...当前的...也许在 SWIFT 中的某些东西 ;-)
猜你喜欢
  • 1970-01-01
  • 2015-11-23
  • 1970-01-01
  • 1970-01-01
  • 2020-04-19
  • 2012-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多