Ответ
Задачи добавляются в DispatchGroup с помощью пары методов enter() и leave(), которые отслеживают количество незавершённых задач. Баланс между вызовами enter() и leave() должен быть строго соблюдён.
Основной паттерн:
- Вызвать
group.enter()непосредственно перед запуском асинхронной задачи. - Вызвать
group.leave()внутри completion handler'а илиdefer-блока этой задачи по её завершении.
let group = DispatchGroup()
let queue = DispatchQueue.global(qos: .userInitiated)
// Задача 1
group.enter() // +1 к счётчику группы
queue.async {
defer { group.leave() } // -1 при выходе из области видимости. Гарантирует вызов.
performLongTask1()
}
// Задача 2 (асинхронная с completion handler)
group.enter()
fetchDataFromNetwork { result in
// Обработка result...
group.leave() // Вызываем после завершения асинхронной работы
}
// Ожидание завершения всех задач и уведомление
group.notify(queue: .main) {
// Этот блок выполнится на главной очереди после того,
// как счётчик группы достигнет нуля.
print("Все задачи завершены")
updateUI()
}
Упрощённый способ с async(group:):
Если задача запускается напрямую через DispatchQueue, можно использовать метод async(group:execute:), который автоматически управляет enter() и leave().
DispatchQueue.global().async(group: group) {
// Эта задача автоматически учтена в группе
performTask()
}
Важно: Используйте defer { group.leave() } для гарантированного вызова, даже если в блоке кода произойдёт ошибка или будет использован return.