Ответ
DispatchGroup — инструмент Grand Central Dispatch (GCD) для синхронизации выполнения группы асинхронных задач. Позволяет дождаться завершения всех задач перед выполнением финального действия.
Ключевые методы:
| Метод | Назначение |
|---|---|
enter() |
Увеличивает внутренний счетчик группы на 1, отмечая начало новой асинхронной задачи. |
leave() |
Уменьшает счетчик на 1, сигнализируя о завершении задачи. Должен вызываться ровно столько раз, сколько enter(). |
notify(queue:execute:) |
Задает замыкание, которое выполнится на указанной очереди, когда счетчик группы станет равным 0. Не блокирует текущий поток. |
wait() |
Блокирует текущий поток до тех пор, пока счетчик группы не станет 0. Может принимать timeout. |
Базовый шаблон использования:
let group = DispatchGroup()
let queue = DispatchQueue.global(qos: .userInitiated)
// Задача 1
group.enter()
queue.async {
defer { group.leave() } // Гарантированный вызов leave()
// Выполнение асинхронной работы
downloadImage(from: url1)
}
// Задача 2
group.enter()
queue.async {
defer { group.leave() }
// Другая асинхронная работа
processData()
}
// Действие после завершения ВСЕХ задач
group.notify(queue: .main) {
// Обновление UI на главном потоке
self.updateInterface()
print("All tasks completed")
}
Важные нюансы:
- Баланс
enter/leave: Несбалансированные вызовы приведут к вечному ожиданию (deadlock) или преждевременному срабатываниюnotify. - Использование
defer: Рекомендуется вызыватьleave()внутриdeferв начале блока задачи, чтобы гарантировать его выполнение даже при возникновении ошибки. wait()vsnotify():wait()блокирует поток и обычно используется в фоновых очередях.notify()— неблокирующий, предпочтителен для большинства сценариев.- Таймаут для
wait():if group.wait(timeout: .now() + 5.0) == .timedOut { print("Tasks took too long") }