Ответ
Да, для этого используется DispatchGroup. Он позволяет отслеживать завершение группы задач и выполнить код, когда все они будут выполнены.
Основные шаги:
- Создать группу:
DispatchGroup() - Войти в группу перед каждой задачей:
enter() - Выйти из группы после завершения каждой задачи:
leave() - Установить обработчик завершения:
notify()или синхронно дождаться:wait()
Пример с асинхронным уведомлением:
let group = DispatchGroup()
// Задача 1
group.enter()
networkService.fetchData { result in
defer { group.leave() } // Гарантирует выход
// Обработка результата
}
// Задача 2
group.enter()
databaseService.loadData { result in
defer { group.leave() }
// Обработка результата
}
// Действие после всех задач
group.notify(queue: .main) {
print("Все асинхронные задачи завершены")
// Обновление UI или продолжение логики
}
Важные моменты:
- Количество вызовов
enter()должно строго соответствовать количествуleave() - Используйте
defer { group.leave() }для гарантированного выхода - Метод
wait()блокирует текущий поток — используйте осторожно - Для работы с
wait()в main thread используйте.async
Ответ 18+ 🔞
Ну, вот смотри, как это работает на самом деле. Есть у тебя, допустим, несколько асинхронных дел — запрос в сеть, чтение из базы, ещё какая-то хуйня. И тебе надо, чтобы после всей этой каши твой код сработал. Не по одному, а когда всё, блядь, наконец-то закончится.
Для этого есть DispatchGroup. Штука, которая считает, сколько задач в работе, и даёт тебе пинок, когда счётчик дошёл до нуля.
Как с ним обращаться, чтобы не обосраться:
- Создаёшь группу:
DispatchGroup()— это как взять табло в спортзале. - Перед каждой задачей, которую нужно отслеживать, говоришь группе: «Внимание, я зашёл!» —
enter(). - После того как задача (обычно в колбэке) выполнилась, не забудь крикнуть: «Я вышел!» —
leave(). Иначе группа будет ждать тебя вечно, как дурак. - И ставишь ловушку —
notify()— которая сработает, когда все, кто зашёл, благополучно вышли.
Вот, смотри, как это выглядит в коде:
let group = DispatchGroup() // Вот твой счётчик, ёпта
// Допустим, первая задача — тащим данные из сети
group.enter() // Зашли в группу
networkService.fetchData { result in
defer { group.leave() } // Выйдем из группы в любом случае, даже если тут пиздец случится
// Тут что-то делаем с результатом...
}
// Вторая задача — ковыряемся в базе
group.enter() // Снова зашли
databaseService.loadData { result in
defer { group.leave() } // И снова гарантированно вышли
// Обрабатываем данные...
}
// И вот магия: когда все зашедшие выйдут, сработает этот блок
group.notify(queue: .main) {
print("Всё, блядь, готово! Можно обновлять интерфейс.")
// Тут уже безопасно лезть в UI
}
А теперь, блядь, важные детали, на которых все обжигаются:
- Количество
enter()иleave()должно быть строго одинаковым. Еслиleave()будет меньше — зависнешь навечно. Если больше — крейш, пиздец.defer— твой лучший друг, он ставитleave()в самое начало очереди на выход из функции. - Есть ещё метод
wait()— он просто блокирует текущий поток и ждёт, пока все задачи не завершатся. НИКОГДА, блядь, НИКОГДА не вызывай его на главном потоке (main), иначе приложение просто встанет колом, и пользователь тебе морду набьёт. Если уж очень надо, оберни вызов вDispatchQueue.global().async. - Всё это хозяйство идеально подходит, когда тебе надо, скажем, скачать десять картинок и только потом собрать из них коллаж. Или отправить пять запросов к разным сервисам и потом слить результаты в кучу.
Вот и вся магия. Не так страшен чёрт, как его малюют. Главное — не забывай выходить из комнаты, когда дело сделано.