NSOperation 依赖和 completionBlock
NSOperation dependency and completionBlock
我们遇到了一个关于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];
这是最终输出
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之前执行。在我们的实际应用中,我们有很多 operation A 而只有一个 operation B 依赖于所有 operation A.但是我们遇到的问题是 operationB 在最后一个 operation A 的完成块被调用之前启动,这通常会给信息操作 B.
如何让 操作 B 在所有 操作 A 的完成块之后执行?
为什么不能调用完成块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];
}
正如您在测试完成块中发现的那样,它们不是 'part of the queue',而是 运行 在操作队列之外(在另一个线程上)。因此,操作 A 的 completionBlock 将 运行 与操作 B 同时(大概)
我建议您重构代码以删除所有完成块。
你说你正在使用 completionBlocks 将信息从操作 A 传递到 B,对此有两种选择: 为 B 提供所有 A 的引用(不是弱的)所以当 B 运行s 它可以从所有 A 中选择结果。或者,如果由于某种原因无法在 B 运行s 之前保留所有 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];
避免完成块 - 它们 out-of-queue 机制不合适
用于同步任何操作或其通信。
引入依赖关系(B 依赖于 A)意味着 B 将仅在 A 成功完成后 运行。
出于这个原因 - 任何简单的数据对象都可以用来在这两个操作之间安全地“传递信息” - 可以简单地共享它(只要你在定义这两个操作的块之外创建它就足够了)操作。当“B”运行s时,它可以假设“A”已经将需要的信息放入数据对象中,并简单地访问它。
self.queue = [[NSOperationQueue alloc] init];
NSMutableDictionary *info = [NSMutableDictionary new]; // data object for communication
NSOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"- Running operation A");
[NSThread sleepForTimeInterval:1.2];
info[@"DoThis"] = @YES;
info[@"DoThat"] = @NO;
NSLog(@"- Done operation A");
}];
NSOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"- Running operation B");
if ([info[@"DoThis"] boolValue] NSLog(@"Op A said to do this.");
if ([info[@"DoThat"] boolValue] NSLog(@"Op A said to do that.");
[NSThread sleepForTimeInterval:2];
NSLog(@"- Done operation B");
}];
[operationB addDependency:operationA];
[self.queue addOperations:@[operationA, operationB] waitUntilFinished:NO];
我们遇到了一个关于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];
这是最终输出
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之前执行。在我们的实际应用中,我们有很多 operation A 而只有一个 operation B 依赖于所有 operation A.但是我们遇到的问题是 operationB 在最后一个 operation A 的完成块被调用之前启动,这通常会给信息操作 B.
如何让 操作 B 在所有 操作 A 的完成块之后执行?
为什么不能调用完成块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];
}
正如您在测试完成块中发现的那样,它们不是 'part of the queue',而是 运行 在操作队列之外(在另一个线程上)。因此,操作 A 的 completionBlock 将 运行 与操作 B 同时(大概)
我建议您重构代码以删除所有完成块。
你说你正在使用 completionBlocks 将信息从操作 A 传递到 B,对此有两种选择: 为 B 提供所有 A 的引用(不是弱的)所以当 B 运行s 它可以从所有 A 中选择结果。或者,如果由于某种原因无法在 B 运行s 之前保留所有 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];
避免完成块 - 它们 out-of-queue 机制不合适 用于同步任何操作或其通信。
引入依赖关系(B 依赖于 A)意味着 B 将仅在 A 成功完成后 运行。
出于这个原因 - 任何简单的数据对象都可以用来在这两个操作之间安全地“传递信息” - 可以简单地共享它(只要你在定义这两个操作的块之外创建它就足够了)操作。当“B”运行s时,它可以假设“A”已经将需要的信息放入数据对象中,并简单地访问它。
self.queue = [[NSOperationQueue alloc] init]; NSMutableDictionary *info = [NSMutableDictionary new]; // data object for communication NSOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"- Running operation A"); [NSThread sleepForTimeInterval:1.2]; info[@"DoThis"] = @YES; info[@"DoThat"] = @NO; NSLog(@"- Done operation A"); }]; NSOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"- Running operation B"); if ([info[@"DoThis"] boolValue] NSLog(@"Op A said to do this."); if ([info[@"DoThat"] boolValue] NSLog(@"Op A said to do that."); [NSThread sleepForTimeInterval:2]; NSLog(@"- Done operation B"); }]; [operationB addDependency:operationA]; [self.queue addOperations:@[operationA, operationB] waitUntilFinished:NO];