Как дождаться завершения всех асинхронных задач перед запуском финальных задач

Я должен быть недоразумение 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
});

Также проверьте эту ссылку для получения дополнительной информации.

Другие вопросы по тегам