Как дождаться завершения всех асинхронных задач перед запуском финальных задач
Я должен быть недоразумение 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 с блоком завершения. Мне нужно бежать runCompletionCheck
после того, как все эти блоки завершения для запросов HealthKit были запущены, но сейчас происходит следующее: runCompletionCheck
выполняется до запуска кода в блоках завершения запросов. Для меня это означает, что dispatch_group_notify
вместе с dispatch_group_async
не работай так, как мне нужно, так что я делаю не так или как лучше всего с этим справиться?
Общая цель: сделать несколько параллельных запросов к HealthKit, запустить их блоки завершения, а затем, когда все эти блоки завершения будут выполнены, запустить метод final.
Проблема в два раза. Во-первых, запросы аптечки не всегда запускают свои блоки завершения. Я начал с использования системы счетчиков со счетчиком в блоках завершения запросов аптечки. Вот что говорит мне, что эти блоки завершения не всегда запускаются. Во-вторых, я не знаю, сколько запросов я пытаюсь выполнить, потому что это зависит от того, какие источники данных есть у пользователя.
Итак, вопрос, как я могу дождаться, пока все блоки завершения из серии запросов набора работоспособности будут выполнены, прежде чем запускать последний метод?
1 ответ
Ваш -getDataForHKQuantity:withCompletion:
Метод асинхронный. Таким образом, через ваши группы рассылки вы синхронизируете вызовы этих методов, а не работу, выполняемую в самих методах.
Другими словами, вы вкладываете два асинхронных вызова, но синхронизируете только первый уровень через группы рассылки.
Вам нужно будет придумать другую стратегию для управления потоком программ.
Два примера:
1. Использование семафоров (блокировка)
Некоторое время назад я использовал семафоры для аналогичной задачи, но не уверен, что это лучшая стратегия, но в вашем случае это будет выглядеть так:
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);
2. Использование dispatch_group
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
});
Также проверьте эту ссылку для получения дополнительной информации.