NSOperation 依赖和completionBlock

Mar*_*ubé 4 objective-c nsoperation nsoperationqueue

我们有一个关于 NSOperationQueue 的简单问题,这是一个简单的操作逻辑:

self.queue = [[NSOperationQueue alloc] init];

NSOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"- Running operation A");
    [NSThread sleepForTimeInterval:1.2];
    NSLog(@"- Done operation A");
}];

NSOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"- Running operation B");
    [NSThread sleepForTimeInterval:2];
    NSLog(@"- Done operation B");
}];

[operationA setCompletionBlock:^{
    NSLog(@"-- Completion Block A");
}];

[operationB setCompletionBlock:^{
    NSLog(@"-- Completion Block B");
}];

[operationB addDependency:operationA];
[self.queue addOperations:@[operationA, operationB] waitUntilFinished:NO];
Run Code Online (Sandbox Code Playgroud)

这是最终的输出

2015-12-21 14:59:57.463 SampleProject[18046:310901] - Running operation A
2015-12-21 14:59:58.664 SampleProject[18046:310901] - Done operation A
2015-12-21 14:59:58.664 SampleProject[18046:310900] - Running operation B
2015-12-21 14:59:58.664 SampleProject[18046:310904] -- Completion Block A
2015-12-21 15:00:00.736 SampleProject[18046:310900] - Done operation B
2015-12-21 15:00:00.736 SampleProject[18046:310904] -- Completion Block B
Run Code Online (Sandbox Code Playgroud)

如我们所见,操作 B操作 A的完成块之前执行。在我们的实际应用程序中,我们有许多操作 A并且只有一个操作 B 依赖于所有操作 A。但是我们遇到的问题是operationB在最后一个操作 A的完成块被调用之前启动,这通常会向操作 B提供信息。

在所有操作 A的完成块之后,如何使操作 B执行?

ale*_*ent 5

正如您在测试完成块中发现的那样,它们不是“队列的一部分”,而是在操作队列之外(并在另一个线程上)运行。因此操作A的completionBlock将与操作B同时运行(ish)。

我建议您重构代码以删除所有完成块。

您说您正在使用 completionBlocks 将信息从操作 A 传递到 B,对此有两种选择: 将 B 引用提供给所有 A(非弱),以便当 B 运行时,它可以从所有 A 中选取结果。或者,如果由于某种原因在 B 运行之前保留所有 A 是不可行的,那么将您的 completionBlock 重新创建为另一个 NSOperation:

NSOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{
    // do stuff
}];

NSOperation *operationATail = [NSBlockOperation blockOperationWithBlock:^{
    // do completionBlock stuff
}];

[operationATail addDependency:operationA];
[operationB addDependency:operationATail];
[self.queue addOperations:@[operationA, operationATail, operationB] waitUntilFinished:NO];
Run Code Online (Sandbox Code Playgroud)