Ответ
В iOS есть три основных подхода:
-
Grand Central Dispatch (GCD) — низкоуровневый C-API для управления очередями.
// Отправка задачи в глобальную фоновую очередь DispatchQueue.global(qos: .userInitiated).async { // Выполнение тяжелой операции let result = processData() // Возврат в главную очередь для обновления UI DispatchQueue.main.async { updateUI(with: result) } } -
OperationQueue — высокоуровневая абстракция на основе GCD, поддерживающая зависимости, отмену и приоритеты.
let queue = OperationQueue() queue.maxConcurrentOperationCount = 2 let operation = BlockOperation { // Выполнение задачи } operation.completionBlock = { print("Готово!") } queue.addOperation(operation) -
Swift Concurrency (async/await) — современный подход, представленный в Swift 5.5.
Task { // Асинхронный вызов let data = await fetchDataFromNetwork() // Автоматически возвращается в MainActor для UI-обновлений updateView(with: data) }
Когда что использовать:
- GCD: Для простых фоновых задач и приоритизации (QoS).
- OperationQueue: Для сложных рабочих процессов с зависимостями между задачами.
- async/await: Для нового кода, требующего читаемости и интеграции с акторами (Actor).
Ответ 18+ 🔞
Слушай, ну вот реально, в айосе с этим асинхронным пиздецом — три главных пути, и все они ведут в ад, но по-разному. Разберём, пока не взорвалась голова.
Первый дед — Grand Central Dispatch (GCD). Это типа старый, проверенный ворчун, низкоуровневый С-шный апи. Кидаешь задачи в очереди — он их жуёт.
// Швыряем тяжёлую работу куда подальше, в фоновую очередь
DispatchQueue.global(qos: .userInitiated).async {
// Тут твой код грузит ядро процессора, ебашит сеть или ещё какую дичь
let result = processData()
// А потом, сука, ВСЕГДА возвращайся на главную очередь, чтобы UI обновить!
DispatchQueue.main.async {
updateUI(with: result)
}
}
Суть в чём: сам всё контролируешь, но и повеситься на этих вложенных замыканиях — проще простого. Читаемость — ноль ебать.
Второй вариант — OperationQueue. Это уже повыше, абстракция поверх GCD. Тут уже можно строить цепочки, отменять операции, лимиты ставить — красота, блядь.
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2 // Чтоб не спалилось всё сразу, только две параллельно
let operation = BlockOperation {
// Делаем дело
}
operation.completionBlock = { print("Готово, нахуй!") } // Выполнится, когда всё ок
queue.addOperation(operation)
Идеально, когда у тебя не просто «сделай раз», а целый рабочий процесс, где одна хуйня зависит от другой. Но и boilerplate-а — овердохуища.
И наконец, новое веяние — Swift Concurrency (async/await). Это как будто из будущего прилетело, в Swift 5.5. Читается почти как обычный код, а работает асинхронно. Магия, ёпта.
Task {
// Просто ждём, когда данные с сети придут. Никаких callback-аддов!
let data = await fetchDataFromNetwork()
// И тут тебя автоматом, по-тихому, возвращает на главный поток для UI
updateView(with: data)
}
Красиво, модно, молодёжно. Но требует поддержки системы и аккуратного обращения с изоляцией данных (эти ваши акторы).
Так когда что брать, чтобы не обосраться?
- GCD: Берёшь, когда задача проще пареной репы — «отправь на фон, потом вернись». Или когда нужно тонко поиграться с приоритетами (QoS).
- OperationQueue: Когда план сложный. «Сначала загрузи A, потом обработай B и C, но только после A, а D можно в любой момент отменить». Вот для такого потока — оно.
- async/await: Для всего нового, что пишешь с нуля. Особенно если код должен быть читаемым и ты не хочешь, чтобы через полгода твой же коллега (или ты сам) хотел тебя ебать в сраку за спагетти из completion-блоков. И да, для работы с акторами — только оно.
Вот и вся философия, блядь. Выбирай по обстановке, а то так и до deadlock’а недалеко.