Как добавить асинхронные задачи в DispatchGroup в Swift?

«Как добавить асинхронные задачи в DispatchGroup в Swift?» — вопрос из категории Многопоточность, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Задачи добавляются в DispatchGroup с помощью пары методов enter() и leave(), которые отслеживают количество незавершённых задач. Баланс между вызовами enter() и leave() должен быть строго соблюдён.

Основной паттерн:

  1. Вызвать group.enter() непосредственно перед запуском асинхронной задачи.
  2. Вызвать 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.