Ответ
Поток выполнения определяется типом очереди (DispatchQueue), в которую отправлен блок.
Основные типы очередей:
| Очередь | Тип | Поток выполнения | Назначение |
|---|---|---|---|
DispatchQueue.main |
Последовательная (serial) | Главный (UI) поток | Все операции с пользовательским интерфейсом. |
| Глобальные очереди ( DispatchQueue.global(qos:)) |
Параллельные (concurrent) | Фоновые потоки из системного пула | Параллельное выполнение нефоновых задач. QoS определяет приоритет. |
| Кастомные очереди ( DispatchQueue(label:)) |
По умолчанию последовательные, но могут быть параллельными | Фоновые потоки из системного пула | Организация и сериализация специфичных задач. |
Примеры:
// 1. Обновление UI на главном потоке.
DispatchQueue.main.async {
self.label.text = "Загрузка завершена"
}
// 2. Выполнение тяжелой задачи в фоне.
DispatchQueue.global(qos: .userInitiated).async {
let processedImage = self.applyFilters(to: largeImage) // В фоновом потоке
// Возврат результата на главный поток для отображения.
DispatchQueue.main.async {
self.imageView.image = processedImage
}
}
// 3. Создание своей последовательной очереди для синхронизации.
let serialQueue = DispatchQueue(label: "com.example.serialQueue")
serialQueue.async {
// Задачи на этой очереди выполняются по одной, в фоновых потоках.
}
Важно: GCD сам управляет созданием, переиспользованием и уничтожением потоков. Разработчик работает только с очередями.
Ответ 18+ 🔞
Давай разжую эту тему про потоки и очереди, чтобы у тебя в голове всё встало на свои места, а не болталось как хуй с винтом. Слушай сюда, но внимательно, а то потом будешь спрашивать, почему UI тормозит.
Вот смотри, есть у тебя код. Он не просто так выполняется, а в каком-то потоке. Поток — это типа рабочая лошадка, которая тащит твои инструкции. А очередь (DispatchQueue) — это, блядь, диспетчер, который решает, на какую лошадку какую телегу навесить.
Какие бывают эти самые диспетчеры-очереди:
| Очередь | Тип | Кто работает? | Зачем нужна? |
|---|---|---|---|
DispatchQueue.main |
Последовательная (serial) | Главный (UI) поток, он один и неповторимый | Всё, что связано с интерфейсом. Только тут можно трогать кнопки, лейблы и прочую визуальную хуйню. |
| Глобальные очереди ( DispatchQueue.global(qos:)) |
Параллельные (concurrent) | Фоновые потоки из общего пула, их дохуя | Для любой тяжелой работы: загрузка, вычисления, обработка фото. QoS — это приоритет, говоришь системе, насколько срочно. |
| Свои, кастомные очереди ( DispatchQueue(label:)) |
По умолчанию последовательные, но можно и параллельные | Тоже фоновые потоки из пула | Чтобы организовать свои задачи в стройную очередь, чтобы они не лезли друг другу в жопу. |
Теперь на живых примерах, чтобы понятно стало:
// 1. Тыкаем в интерфейс. ТОЛЬКО НА ГЛАВНОЙ, СУКА!
DispatchQueue.main.async {
self.label.text = "Всё, загрузилось, можно выдыхать"
// Если это сделать не на главной — получишь краш, и будет тебе ебаный вротберунчик.
}
// 2. Делаем что-то тяжелое, не задерживая главный поток.
DispatchQueue.global(qos: .userInitiated).async {
// Допустим, фильтруем огромную фотку. Делаем это в фоне.
let processedImage = self.applyFilters(to: largeImage)
// Как закончили — ОБЯЗАТЕЛЬНО возвращаем результат на главную, чтобы показать.
DispatchQueue.main.async {
self.imageView.image = processedImage // Вот теперь можно.
}
}
// 3. Создаём свою очередь, чтобы задачи шли строго по одной.
let serialQueue = DispatchQueue(label: "com.example.mySerialQueue")
serialQueue.async {
// Задача 1
}
serialQueue.async {
// Задача 2 начнётся ТОЛЬКО после задачи 1. Порядок, блядь!
}
Самое главное, что нужно вынести: ты, как разработчик, не паришься о создании потоков. Ты кидаешь задачи (async) в очереди, а система (GCD) сама решает, какой свободный поток из пула ей для этого использовать, создавать новый или переиспользовать старый. Твоя работа — правильно выбрать очередь.
Запомни простое правило: UI — только main, всё остальное — в global или свою очередь. Нарушишь — получишь лагующий интерфейс и пользователей, которые захотят тебя ебать в сраку. Всё гениальное просто.