我必须计算一个代价高昂的价值。计算此值后,我想运行完成处理程序块:
-(void) performCostlyCalculationWithCompletionHandler:(void (^)(void)complete
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
id result = [self costlyCalculation];
dispatch_async(dispatch_get_main_queue(), ^{
complete(result);
});
});
}
非常标准。
现在,我希望能够重复调用此函数,而无需重新入列costlyCalculation
。如果costlyCalculation
已在运行,我只想保存完成块,并在result
完成后使用相同的costlyCalculation
全部调用它们。
使用GCD或NSOperationQueue有一种简单的方法吗?或者我应该将完成块存储在NSArray
中并自己调用它们?如果我这样做,我需要在这个数组周围进行什么样的同步?
更新
我能够与dispatch_group_notify
取得联系。基本上,我可以将工作块排队并将所有完成处理程序排入队列之后运行:
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queue, ^(){
// Do something that takes a while
id result = [self costlyCalculation];
dispatch_group_async(group, dispatch_get_main_queue(), ^(){
self.result = result;
});
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^(){
complete(result);
});
这样可行,但如果我不需要,我怎么能判断costlyCalcuation
是否已经在运行并且不会将工作排入队列?
答案 0 :(得分:1)
我认为你已经解决了这个问题。我刚刚想出了一个使用NSOperationQueue和NSOperations之间依赖关系的替代方案。这是我认为的伪代码。
// somewhere, create operation queue
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
-(void)tryCalculation:(CompletionBlockType)completionBlock
{
if(opQueue.operationCount > 0)
{
NSOperation *op = [[NSOperation alloc] init];
op.completionBlock = completionBlock;
// you can control how to synchronize completion blocks by changing dependency object. In this example, all operation will be triggered at once when costly calculation finishes
[op addDependency:[opQueue.operations firstObject]];
[opQueue addOperation:op];
}
else
{
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(costlyCalculation) object:nil];
op.completionBlock = completionBlock;
[opQueue addOperation:op];
}
}
仍然存在微妙的时间问题。也许我们可以在昂贵的计算函数中使用额外的标志。