Вопрос проверяет умение координировать параллельные операции и правильно собирать результаты без гонок и преждевременного завершения.
В GCD для этого используют DispatchGroup. Каждая задача “входит” в группу перед стартом и “выходит” после завершения. Когда все вышли, вызывается notify, где можно собрать результаты и обновить UI. В Swift Concurrency аналогом является async let или TaskGroup. Важно корректно управлять потокобезопасностью при записи результатов.
Задача “подождать несколько асинхронных операций” встречается постоянно: загрузить несколько ресурсов, выполнить пачку запросов, собрать данные для экрана.
DispatchGroup (GCD)Создаем группу
Для каждой задачи делаем enter
В completion делаем leave
В notify получаем сигнал “все готово”
Пример:
let group = DispatchGroup()
var resultA: Data?
var resultB: Data?
group.enter()
loadA { data in
resultA = data
group.leave()
}
group.enter()
loadB { data in
resultB = data
group.leave()
}
group.notify(queue: .main) {
// здесь гарантированно завершены A и B
// можно собрать результаты
}
Если результаты пишутся с разных потоков, стоит:
писать результаты на serial queue
или синхронизировать доступ (например, через barrier/serial queue)
async letПодходит, когда есть фиксированное число задач.
async let a = fetchA()
async let b = fetchB()
let (ra, rb) = await (a, b)
// здесь обе завершены
withTaskGroupПодходит, когда задач много и их число динамическое.
можно добавлять задачи в цикле
собирать результаты по мере завершения
Проект на GCD/старый код: DispatchGroup
Современный код: async let / TaskGroup
Нужны отмена и structured concurrency: предпочитать Swift Concurrency
Чтобы дождаться завершения нескольких асинхронных операций, нужен координирующий механизм: в GCD это DispatchGroup, в Swift Concurrency — async let и TaskGroup. Ключевые ошибки в таких задачах — забыть leave, обновить UI не на main, или получить гонку данных при записи результатов. Правильная координация делает код предсказуемым, ускоряет загрузку за счет параллелизма и упрощает поддержку.