Я хочу, чтобы код в группе диспетчеризации завершил выполнение до того, как что-то еще произойдет, по сути, блокируя приложение от выполнения каких-либо действий до выполнения этого кода. Однако я не могу заставить группу отправки блокировать запуск дополнительного кода. Я попробовал почти все предложения здесь в стеке, но я не знаю, чего я хочу.
Моя функция:
- (void)myFunction {
NSString *myString = @"Hello world";
dispatch_group_t group = dispatch_group_create();
NSLog(@"1 entering the dispatch group");
dispatch_group_enter(group);
[self doSomething:myString completion:^{
dispatch_group_leave(group);
NSLog(@"2 we have left the dispatch group");
}];
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"3 notifying that the dispatch group is finished");
}];
NSLog(@"4 all process are complete, we are done");
}
Вывод я хочу через лог операторов = 1,2,3,4
Вывод получаю через лог операторов = 1,4,2,3
Почему мой код пропускает группу рассылки и печатает 4 до 2 и 3? Любой совет относительно того, что я делаю неправильно, приветствуется. Спасибо!
< Сильный > Update :
Вот мой метод doSomething
. Мой код продолжает зависать при вызове dismiss
.
doSomething() {
viewController.dismiss(animated: false completion: { [weak self] in
doMoreCode()
})
}
2 ответа
Ничто здесь на самом деле не блокирует. dispatch_group_notify
просто говорит: «Когда группа закончит, запустите это». Инструмент, который вы намеревались использовать, был dispatch_group_wait
. Если вы хотите 1,2,3,4, то вы имели в виду это:
- (void)myFunction {
NSString *myString = @"Hello world";
dispatch_group_t group = dispatch_group_create();
NSLog(@"1 entering the dispatch group");
dispatch_group_enter(group);
[self doSomething:myString completion:^{
NSLog(@"2 we have left the dispatch group");
dispatch_group_leave(group);
}];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"3 notifying that the dispatch group is finished");
NSLog(@"4 all process are complete, we are done");
}
myFunction
, конечно, нельзя вызвать в главной очереди в iOS (поскольку он блокируется, и вы никогда не должны блокировать основную очередь). И он также не должен вызываться в той же очереди, которую doSomething:completion:
использует для своего обработчика завершения (поскольку эта очередь будет заблокирована в dispatch_group_wait
).
Помните, что dispatch_queue_notify
просто добавляет блок в очередь для запуска в будущем. Так что немного неясно, как вы ожидаете, что 3 и 4 будут работать (в моем примере я просто свернул их, но, возможно, вы ищете что-то еще).
Другой подход состоит в том, чтобы не блокировать приложение, а просто запланировать запуск вещей, когда это необходимо. В этом случае вы можете использовать основную очередь. Это будет выглядеть так:
- (void)myFunction {
NSString *myString = @"Hello world";
dispatch_group_t group = dispatch_group_create();
NSLog(@"1 entering the dispatch group");
dispatch_group_enter(group);
[self doSomething:myString completion:^{
NSLog(@"2 we have left the dispatch group");
dispatch_group_leave(group);
}];
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"3 notifying that the dispatch group is finished");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"4 all process are complete, we are done");
});
}
Обратите внимание, что в обоих примерах я записываю 2 перед вызовом dispatch_group_leave
. В этом примере я также регистрирую две вещи, которые будут выполняться в главной очереди (по порядку) после создания группы. В этом случае myFunction
немедленно вернется (чтобы его можно было запустить в главной очереди), но все должно распечатываться по порядку.
Предполагая, что doSomething
выполняется асинхронно, вы можете подождать группу, но обычно лучше использовать асинхронные шаблоны, например, позвольте myFunction
немедленно вернуться, но предоставьте свой собственный обработчик завершения для этого метода:
- (void)myFunctionWithCompletion:(void (^)())completion {
NSString *myString = @"Hello world";
dispatch_group_t group = dispatch_group_create();
NSLog(@"1 entering the dispatch group");
dispatch_group_enter(group);
[self doSomething:myString completion:^{
dispatch_group_leave(group);
NSLog(@"2 we have left the dispatch group");
}];
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"3 notifying that the dispatch group is finished");
});
}
И используйте это так:
[self myFunctionWithCompletion:^{
NSLog(@"4 all process are complete, we are done");
}];
// note, it's not done when it gets here, though, because it's asynchronous
Понятно, что в приведенном выше примере группа рассылки совершенно лишняя, но я предполагаю, что вы выполняли несколько асинхронных задач, поэтому вы представили группу рассылки. Если бы это действительно была только эта асинхронная задача, вы бы просто сделали:
- (void)myFunctionWithCompletion:(void (^)())completion {
NSString *myString = @"Hello world";
[self doSomething:myString completion:^{
NSLog(@"The asynchronous doSomething is done");
completion();
}];
}
Похожие вопросы
Новые вопросы
ios
iOS - мобильная операционная система, работающая на Apple iPhone, iPod touch и iPad. Используйте этот тег [ios] для вопросов, связанных с программированием на платформе iOS. Используйте связанные теги [target-c] и [swift] для проблем, характерных для этих языков программирования.