Для чего используется DispatchGroup в Grand Central Dispatch (GCD)?

Ответ

DispatchGroup — это механизм GCD для синхронизации группы асинхронных или параллельных задач. Он позволяет отслеживать завершение произвольного количества задач и выполнить финальный блок кода, когда все они будут закончены.

Основные методы:

  • enter(): Увеличивает внутренний счетчик группы (начало задачи).
  • leave(): Уменьшает счетчик (завершение задачи).
  • notify(queue:execute:): Запланировать блок кода, который выполнится, когда счетчик станет равен нулю.
  • wait(): Синхронно блокирует текущий поток до завершения всех задач группы (использовать с осторожностью).

Типичный use case: Загрузка данных из нескольких источников.

let imageGroup = DispatchGroup()
var downloadedImages: [UIImage] = []

// Задача 1: Загрузка аватара
imageGroup.enter()
networkService.loadAvatar { image in
    downloadedImages.append(image)
    imageGroup.leave()
}

// Задача 2: Загрузка обложки
imageGroup.enter()
networkService.loadCover { image in
    downloadedImages.append(image)
    imageGroup.leave()
}

// Действие после завершения ВСЕХ загрузок
imageGroup.notify(queue: .main) {
    // Все изображения загружены, счетчик = 0
    self.updateUI(with: downloadedImages)
    print("Все изображения готовы")
}
// Основной поток не блокируется.

Ключевые моменты:

  • Каждый enter() должен быть сбалансирован соответствующим leave().
  • notify() — это асинхронный метод, он не блокирует вызывающий поток.
  • Идеально подходит для агрегации результатов нескольких независимых асинхронных операций.

Ответ 18+ 🔞

А, ну вот, смотри, опять эти ваши группы диспетчерские, блядь. DispatchGroup, сука. Это ж как будто ты в армии командируешь отделением, а они все по кустам разбежались, и тебе надо понять, когда они все, биздюны, обратно приползут, чтобы дальше маршировать.

Короче, это такая штука, чтобы синхронизировать кучу асинхронных дел. Представь, ты отправил пять запросов на сервер, и тебе надо дождаться, пока все пять, блядь, ответят, и только потом UI обновить. Вот для этого он и есть.

Основные команды, которые у него есть:

  • enter(): Это ты как бы говоришь: «Так, блядь, ещё один солдат ушёл в самоволку, за ним следим!». Внутренний счётчик увеличивается.
  • leave(): А это когда солдат вернулся, весь в соплях, и говорит: «Я тут». Счётчик уменьшается.
  • notify(queue:execute:): Это твоя команда, которую ты даёшь заранее: «Ребята, как только все вернутся — сразу на тусовку!». Этот блок выполнится, когда счётчик станет ноль.
  • wait(): Это самый жёсткий метод, ёпта. Ты просто встаёшь и говоришь: «Я тут постою, пока все не придут». И текущий поток замирает нахуй, пока все задачи не завершатся. Использовать осторожно, а то зафризишь всё.

Типичная история: качаешь картинки с разных мест.

let imageGroup = DispatchGroup()
var downloadedImages: [UIImage] = []

// Задача 1: Качаем аватарку
imageGroup.enter() // Говорим: "Так, первая картинка пошла качаться, следим!"
networkService.loadAvatar { image in
    downloadedImages.append(image)
    imageGroup.leave() // Говорим: "Всё, эта пришла, можно вычёркивать!"
}

// Задача 2: Качаем обложку
imageGroup.enter() // "Так, вторая тоже ушла в сеть!"
networkService.loadCover { image in
    downloadedImages.append(image)
    imageGroup.leave() // И эта вернулась!
}

// И вот самое важное — что делать, когда ВСЕ наконец-то приползли?
imageGroup.notify(queue: .main) {
    // Опа, счётчик ноль! Все картинки в массиве downloadedImages.
    self.updateUI(with: downloadedImages)
    print("Ну наконец-то, все изображения готовы, можно людей радовать!")
}
// И главное — основной поток тут не тормозит, он свободен, пока эти все там качаются.

Что важно помнить, чтобы не обосраться:

  • На каждый enter() должен быть свой leave(). Иначе счётчик не обнулится, и твой notify никогда не сработает, будешь ждать как лох.
  • notify() — он асинхронный, умный. Он не будет тебя тут держать, он просто поставит напоминалку и пошёл дальше.
  • Идеальная вещь, когда тебе надо собрать результаты кучи независимых операций в одну кучу и потом что-то с ней сделать. Просто красота, а не инструмент.