Ответ
В GCD (Grand Central Dispatch) в iOS/Swift существует два основных типа очередей, классифицируемых по способу выполнения задач:
1. Последовательные очереди (Serial Queues)
Задачи выполняются строго одна за другой в порядке добавления.
- Главная очередь (Main Queue): Глобальная последовательная очередь, связанная с основным потоком. Все операции с UI должны выполняться на ней.
DispatchQueue.main.async { self.label.text = "Updated" // Безопасное обновление UI } - Пользовательские последовательные очереди (Custom Serial Queues): Создаются разработчиком.
let serialQueue = DispatchQueue(label: "com.app.serialQueue") // По умолчанию .serial serialQueue.async { print("Task 1") } serialQueue.async { print("Task 2") } // "Task 2" начнется только после завершения "Task 1"
2. Параллельные очереди (Concurrent Queues)
Задачи могут выполняться одновременно на нескольких потоках.
-
Глобальные параллельные очереди (Global Concurrent Queues): Системные очереди с разными уровнями приоритета (Quality of Service - QoS). QoS Приоритет Назначение .userInteractiveВысший Анимации, мгновенный отклик на действия пользователя. .userInitiatedВысокий Задачи, инициированные пользователем, требующие быстрого результата. .defaultСредний Задачи по умолчанию. .utilityНизкий Длительные задачи (загрузка, вычисления) с индикатором прогресса. .backgroundСамый низкий Фоновые задачи, невидимые пользователю (синхронизация, чистка). DispatchQueue.global(qos: .utility).async { let data = self.loadDataFromNetwork() // Долгая задача DispatchQueue.main.async { self.updateUI(with: data) } // Возврат на main } - Пользовательские параллельные очереди (Custom Concurrent Queues): Создаются разработчиком.
let concurrentQueue = DispatchQueue(label: "com.app.concurrent", attributes: .concurrent) concurrentQueue.async { print("Task A") } concurrentQueue.async { print("Task B") } // "Task A" и "Task B" могут выполняться параллельно
Ответ 18+ 🔞
О, давай разберём эту всю хуйню с очередями в GCD, а то смотрю, народ путается как слепой в борделе.
Смотри, есть всего два типа, как яйца у петуха — последовательные и параллельные. И всё, блядь.
Первые — последовательные (Serial Queues). Это как очередь в один единственный сортир на вокзале. Пока один не выйдет, следующий не зайдёт, хоть обосрись. Задачи выполняются строго по очереди, одна за другой.
Тут у нас две главных звезды:
- Главная очередь (Main Queue). Это святое, блядь! Это тот самый единственный поток, который может трогать твой интерфейс. Всё, что связано с кнопками, лейблами, анимациями — ВСЁ на неё. Если полезешь с этим из другого потока — получишь краш, и будет тебе как Герасиму с Муму, только в мире iOS.
DispatchQueue.main.async { self.label.text = "Updated" // Вот так, блядь, правильно. Сперва делаешь всю тяжёлую работу где-то в подворотне, а потом на главную — обновить морду. } - Свои, кастомные последовательные очереди. Создаёшь сам, называешь как хочешь. Удобно, когда нужно, чтобы задачи не лезли друг другу в жопу, а выполнялись чинно-благородно.
let serialQueue = DispatchQueue(label: "com.app.serialQueue") // По умолчанию она уже последовательная serialQueue.async { print("Task 1 — я первый в сортире!") } serialQueue.async { print("Task 2 — я буду ждать, пока тот кончит!") } // Task 2 начнётся только после Task 1.
Вторые — параллельные (Concurrent Queues). Это уже как общественный туалет с десятью кабинками. Забегает куча народу, и каждый делает своё дело одновременно. Задачи могут выполняться в несколько потоков.
И тут тоже два лагеря:
-
Глобальные параллельные очереди (Global Concurrent Queues). Это системные, готовые очереди. У них разный приоритет, или, как они там выёбываются, «Quality of Service» (QoS). Чтобы не запоминать, смотри табличку, я для тебя, ленивая жопа, её приготовил:
QoS Приоритет Для чего, блядь? .userInteractiveВысший Всё, что должно быть мгновенно: анимации, отклик на тап. Пользователь ждать не должен. .userInitiatedВысокий Пользователь что-то нажал и ждёт быстрого результата (открыть документ). .defaultСредний Ну... по умолчанию. Если не знаешь — ставь это. .utilityНизкий Долгие дела, где можно показать прогресс-бар: загрузка, вычисления. .backgroundСамый низкий Фоновая работа, которую пользователь даже не видит: синхронизация, чистка кэша. Пример, чтобы не быть просто пиздаболом:
DispatchQueue.global(qos: .utility).async { let data = self.loadDataFromNetwork() // Сиди тут, грузись, не мешай интерфейсу DispatchQueue.main.async { self.updateUI(with: data) } // А как загрузил — марш на главную, обновлять экран! } - Свои, кастомные параллельные очереди. Создал, указал атрибут
.concurrent— и вуаля, можешь запускать задачи пачками.let concurrentQueue = DispatchQueue(label: "com.app.concurrent", attributes: .concurrent) concurrentQueue.async { print("Task A — я пошёл!") } concurrentQueue.async { print("Task B — и я тоже пошёл! Мы можем работать вместе!") } // Оба могут выполняться одновременно.
Вот и вся магия, ёпта. Главное — запомни: с UI работаешь только на главной очереди, а всю тягомотину скидывай в глобальные с подходящим приоритетом. А то накосячишь — и будет тебе не мультитрединг, а один сплошной пиздец.