【问题标题】:Do NSOperations and their completionBlocks run concurrently?NSOperations 和它们的完成块是否同时运行?
【发布时间】:2012-07-09 22:05:03
【问题描述】:

我有一堆NSOperations 添加到NSOperationQueue。操作队列将maxConcurrentOperationCount 设置为1,以便NSOperations 一个接一个地运行。

现在,在NSOperationcompletionBlock 中,我想通过在NSOperationQueue 上调用cancelAllOperations 来取消所有待处理的NSOperations

这样做安全吗?我能确定下一个操作的start-方法只有在上一个操作的completionBlock完全执行后才被调用吗?还是上一个操作的completionBlock和当前操作的任务并发运行?

我问的原因:我使用 AFNetworking 执行了一批AFHTTPRequestOperations,并且只想在该批次的所有先前请求都成功的情况下才执行一个请求。

【问题讨论】:

    标签: nsoperation nsoperationqueue afnetworking


    【解决方案1】:

    我想出了另一种看似更好的方法,以确保仅在满足某些条件(基于先前完成的操作的结果)时才执行操作,否则操作被取消。

    这里一个重要的考虑是,运行操作的条件检查不应该在操作子类中编码,从而允许操作子类在不同的场景和应用程序之间移植。

    解决方案: - 在子类中具有条件块属性,并设置实例化操作的任何条件形式。 - 覆盖 NSOperation 子类的“isReady”getter,检查那里的条件,从而确定它是否准备好执行。 - 如果[super isReady]为YES,表示依赖操作全部完成,则评估必要条件。 - 如果条件检查通过,返回YES。否则,将 isCancelled 设置为 YES 并为 isReady 返回 YES

    代码: 在接口文件中有block属性:

    typedef BOOL(^ConditionBlock)(void);
    
    @property (copy) ConditionBlock conditionBlock;
    

    在实现中,覆盖isReady,并取消:

    @implementation ConditionalOperation
    
    - (BOOL)isReady {
            if([super isReady]) {
                if(self.conditionBlock) {
                    if(!self.conditionBlock()) {
                        [self setCancelled:YES];
                    }
                    return YES;
                } else {
                    return YES;
                }
            } else {
                return NO;
            }
        }
    

    【讨论】:

      【解决方案2】:

      NSOperation 仅基于操作的完成状态不基于已完成操作的结果建立依赖关系。

      但是,我遇到的大多数场景都是这样的,操作的执行不仅取决于其他一些操作的完成,还取决于从完成的操作中获得的结果。

      我最终做了下面的方法,但仍在探索是否有更好的方法:

      1) 操作-A 运行

      2) 操作-A 完成并且它的completionBlock 运行

      3) 在 OperationA 的完成块中,检查从 Operation-A 获得的结果。

      • 如果结果为 X,则创建 Operation-B 并添加到队列中。
      • 如果结果为 Y,则创建 Operation-C 并添加到队列中。
      • 如果结果错误,则创建操作-D(通常是警报操作)并添加到队列中

      因此,这最终成为一系列操作,根据已完成操作的结果动态添加到队列中。

      【讨论】:

      • 很好的解决方案!
      【解决方案3】:

      我在下面的发现似乎不再正确。我在 iOS 8 和 iOS 9 上重新运行了测试,并且操作的完成块始终与下一个操作同时运行。目前,我没有看到让操作等待前一个完成块完成的方法。


      我刚刚在一个示例项目中尝试了这种情况。结果如下:

      如果NSOperationQueuemaxConcurrentOperationCount 设置为1,则NSOperationcompletionBlock 和队列中的下一个NSOperation 同时运行。

      但是,如果每个 NSOperation 都通过调用 addDependency: 链接到其前一个操作,则操作的执行将等待前一个操作的 completionBlock 完成。

      所以,如果你想取消当前操作的completionBlock中的下一个操作,并确保它在启动之前被取消,你必须通过调用addDependency:来设置NSOperations之间的依赖关系

      【讨论】:

      • 很好的分析!刚刚经历了同样的事情。
      • 这似乎不是真的,至少对于 iOS 9 来说不是。我有一个完成块,我可能想取消依赖操作,但它通常在完成块之前已经开始执行运行。
      • 你说得对,我重新运行了我的实验,现在完成块和下一个操作总是并行运行。
      • 我猜你可以控制依赖操作中的ready 属性并公开一个翻转它的方法(使用KVO)从完成块中调用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-30
      • 1970-01-01
      • 2017-01-08
      • 1970-01-01
      相关资源
      最近更新 更多