NSOperations及其completionBlocks同时运行吗?

时间:2012-07-10 12:18:12

标签: nsoperation nsoperationqueue afnetworking

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

现在,在completionBlock的{​​{1}}中,我想通过NSOperation上的NSOperations取消所有待审cancelAllOperations

这样做是否安全?我是否可以确定只有在前一个操作的NSOperationQueue完全执行后才调用下一个操作的start - 方法?或者执行上一个操作的completionBlock并同时运行当前操作的任务?

我之所以要问:我使用AFNetworking来执行一批completionBlock,并且只有在批量的所有先前请求都成功时才想执行一个请求。

3 个答案:

答案 0 :(得分:5)

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


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

如果NSOperationQueue的{​​{1}}设置为1,则maxConcurrentOperationCount的{​​{1}}和队列中的下一个NSOperation会同时运行。

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

因此,如果要取消当前操作的addDependency:中的下一个操作并确保在启动之前取消它,则必须通过调用在completionBlock之间设置依赖关系completionBlock

答案 1 :(得分:1)

NSOperation仅根据操作的完成状态建立依赖性,而不根据完成的操作结果建立依赖性

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

我最终按照以下方法进行操作,但仍在探索是否有更好的方法:

1)操作A运行

2)Operation-A参与竞争,completionBlock运行

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

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

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

答案 2 :(得分:1)

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

这里的一个重要考虑因素是,不应在操​​作子类中编写用于运行操作的条件检查的代码,这样可以使操作子类在不同的场景和应用程序之间相互兼容。

解决方案: -在子类内部具有条件块属性,并设置实例化操作的任何条件形式。 -重写NSOperation子类的“ isReady” getter,检查那里的条件,从而确定其是否准备好执行。 -如果[super isReady]为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;
        }
    }