的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所有操作的的结束块之后执行?
,正如你在测试完成块已经发现不是“排队”的一部分,而不是它们运行的操作队列之外(和另一个线程)。因此,操作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];
好吧描述。这正是我最终做的事情(我实际上在那些已经存在的操作之上创建了自定义的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];
}
因为,如上所述,我可能有多个操作A的且只有一个操作B.我不希望每个操作A有1个操作B,这是否有意义? –
那么为什么不按照需要以不同的方式设置完成块。所以每次你需要操作b在操作完成后运行,然后设置操作a的完成块以满足你的需要。 – Reedy
在切换到GCD的选项?该API具有您需要的所有工具。对于这个特殊情况,障碍块是你正在寻找的东西。通过这些,您可以并行运行多个A类任务,然后添加B类障碍任务,在完成所有A之前无法启动,并且在B完成之前无法启动新任务。 – pco494
你能给我一个简单的例子,说明它是如何工作的吗?我对GCD有所了解,但对于这种任务还不够。 –
老实说,我也不是专家,但我读了[教程](http://www.raywenderlich.com/60749/grand-central-dispatch-in -depth-part-1)Ray Wenderlich在第二部分“处理读者和作家问题”中讨论了一些与你正在寻找的东西完全相同的东西。 – pco494