我必须误解dispatch_group
,因为我的dispatch_group_notify
调用在单个dispatch_group_async
块内的异步调用结束之前正在运行。这是我的代码:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t dispatchGroup = dispatch_group_create();
// create operation for each HKTypeIdentifier for which we want to retrieve information
for( NSString *hkType in typesToRetrieve){
dispatch_group_async(dispatchGroup, queue, ^{
// this method runs several HK queries each with a completion block as indicated below
[self getDataForHKQuantity: hkType withCompletion:^(NSArray *results) {
// this completion blocks runs asynchronously as HK query completion block
// I want to runCompletionBlock only after
// all these processResultsArray calls have finished
[self processResultsArray:results];
}];
});
}
dispatch_group_notify(dispatchGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self runCompletionCheck];
});
方法getDataForHKQuantity
依次使用完成块向HealthKit运行异步查询。在运行HealthKit查询的所有这些完成块之后,我需要运行runCompletionCheck
,但现在发生的事情是runCompletionCheck
在查询中的代码之前运行。完成块已运行。对我来说,这意味着dispatch_group_notify
以及dispatch_group_async
不能按我需要的方式工作,那么我做错了什么或者处理这个问题的最佳方法是什么?
总体目标:向HealthKit发出一堆并发查询,运行完成块,然后运行所有这些完成块时,运行最终方法。
这个问题有两个问题。 首先,健康工具包查询并不总是运行完成块。我开始使用计数器系统,在健康工具包查询中有一个计数器。完成块。这就是告诉我这些完成块不会一直运行的原因。 其次,我不知道我尝试运行多少查询,因为它取决于用户拥有的数据源。
那么,问题是,在运行最终方法之前,如何运行一系列运行状况工具包查询中的所有完成块?
答案 0 :(得分:3)
您的-getDataForHKQuantity:withCompletion:
方法是异步的。因此,通过您的调度组,您正在将调用同步到这些方法,而不是在方法本身中完成的工作。
换句话说,您正在嵌套两个异步调用,但只通过调度组同步第一个级别。
您需要提出一个不同的策略来控制您的程序流程。
两个例子:
前段时间,我使用信号量进行类似的任务,不确定这是最好的策略,但在你的情况下它会像:
semaphore = dispatch_semaphore_create(0);
for( NSString *hkType in typesToRetrieve)
{
[self getDataForHKQuantity: hkType withCompletion:^(NSArray *results) {
// register running method here
[self processResultsArray:results];
if (isLastMethod) // need to keep track of concurrent methods running
{
dispatch_semaphore_signal(semaphore);
}
}];
}
// your program will wait here until all calls to getDataForHKQuantity complete
// so you could run the whole thing in a background thread and wait for it to finish
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_t serviceGroup = dispatch_group_create();
for( NSString *hkType in typesToRetrieve)
{
dispatch_group_enter(serviceGroup);
[self getDataForHKQuantity: hkType withCompletion:^(NSArray *results) {
[self processResultsArray:results];
dispatch_group_leave(serviceGroup);
}];
}
dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
// Won't get here until everything has finished
});
另请查看this link以获取更多信息。