的NSOperation依赖和completionBlock

问题描述:

我们有关于NSOperationQueue一个简单的问题,这里有一个简单的操作逻辑:的NSOperation依赖和completionBlock

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]; 

下面是最终输出

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 

正如我们所看到的,操作B操作A的completionBlock之前执行。在我们的实际应用中,我们有很多操作的,只有一个动作B是依赖于所有操作的。但是接下来我们遇到的问题是操作B在最后的操作之前启动A的完成块已被调用,它通常会提供信息给操作B

我怎么会让动作B所有操作的的结束块之后执行?

+0

在切换到GCD的选项?该API具有您需要的所有工具。对于这个特殊情况,障碍块是你正在寻找的东西。通过这些,您可以并行运行多个A类任务,然后添加B类障碍任务,在完成所有A之前无法启动,并且在B完成之前无法启动新任务。 – pco494

+0

你能给我一个简单的例子,说明它是如何工作的吗?我对GCD有所了解,但对于这种任务还不够。 –

+0

老实说,我也不是专家,但我读了[教程](http://www.raywenderlich.com/60749/grand-central-dispatch-in -depth-part-1)Ray Wenderlich在第二部分“处理读者和作家问题”中讨论了一些与你正在寻找的东西完全相同的东西。 – pco494

,正如你在测试完成块已经发现不是“排队”的一部分,而不是它们运行的​​操作队列之外(和另一个线程)。因此,操作A的completionBlock将与操作B同时运行(ish)。

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

你说你正在使用completionBlocks将信息从操作A传递给B,有两种选择:给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]; 
+0

好吧描述。这正是我最终做的事情(我实际上在那些已经存在的操作之上创建了自定义的NSOperation子类)。我得说,这样更干净。我忘了在我的回答中解释,所以谢谢你的支持。 –

为什么你不能调用完成块a内部的操作,那就是完成块的作用。

[operationA setCompletionBlock:^{ 
    NSLog(@"-- Completion Block A"); 
    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
    NSOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{ 
     NSLog(@"- Running operation B"); 
     [NSThread sleepForTimeInterval:2]; 
     NSLog(@"- Done operation B"); 
    }]; 
    [queue addOperations:@[operationB] waitUntilFinished:NO]; 
}]; 


[operationA setCompletionBlock:^{ 
    NSLog(@"-- Completion Block A when we dont need B"); 
}]; 

有一些更好的执行这个方法通过,而不是使用

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    [self operationB]; 
} 
+0

因为,如上所述,我可能有多个操作A的且只有一个操作B.我不希望每个操作A有1个操作B,这是否有意义? –

+0

那么为什么不按照需要以不同的方式设置完成块。所以每次你需要操作b在操作完成后运行,然后设置操作a的完成块以满足你的需要。 – Reedy