Ответ
Экосистема iOS предоставляет несколько инструментов для работы с многопоточностью, от низкоуровневых до современных высокоуровневых API.
1. Grand Central Dispatch (GCD) Фреймворк для управления очередями (очередями задач).
// Выполнение задачи в фоновом потоке
DispatchQueue.global(qos: .userInitiated).async {
let processedData = expensiveCalculation()
// Возврат результата в главный поток для обновления UI
DispatchQueue.main.async {
self.updateUI(with: processedData)
}
}
2. Operation и OperationQueue Более высокоуровневая абстракция над GCD, поддерживающая зависимости между операциями, отмену и наблюдение за состоянием.
let downloadOp = BlockOperation { /* Загрузка */ }
let processOp = BlockOperation { /* Обработка */ }
processOp.addDependency(downloadOp) // Обработка начнется только после загрузки
let queue = OperationQueue()
queue.addOperations([downloadOp, processOp], waitUntilFinished: false)
3. Swift Concurrency (async/await, Actors) Современный, безопасный и выразительный способ, представленный в Swift 5.5.
// Async функция
func fetchUserData() async throws -> UserData {
let data = try await networkService.request(.userProfile) // Без callback hell
return try JSONDecoder().decode(UserData.self, from: data)
}
// Использование
Task {
do {
let user = try await fetchUserData()
await MainActor.run { // Гарантированное выполнение на главном потоке
self.user = user
}
} catch {
// Обработка ошибки
}
}
// Actor для защиты общих ресурсов
actor Counter {
private var value = 0
func increment() { value += 1 }
func getValue() -> Int { return value }
}
Выбор инструмента:
- Swift Concurrency — предпочтительный выбор для нового кода, поддерживающего iOS 13+ (с
@available). - GCD — для простых фоновых задач или поддержки legacy-кода.
- OperationQueue — для сложных зависимых операций.
Ответ 18+ 🔞
Слушай, а ведь в айосе с многопоточностью вообще отдельная песня, там целый зоопарк инструментов, от таких, что прям в ядро лезут, до современных штук, где можно почти на человеческом языке писать. Давай разбираться, пока не взорвалась голова.
1. Grand Central Dispatch (GCD) Это типа фундамент, классика жанра. Работает на очередях — скидываешь туда задачки, а система сама решает, когда и в каком потоке их жахнуть. Просто, но мощно.
// Кидаем тяжёлую работу куда подальше с глаз долой (в фон)
DispatchQueue.global(qos: .userInitiated).async {
let processedData = expensiveCalculation() // тут твой процессор плавится
// А как результат готов — быстрее пули назад на главный, UI обновлять!
DispatchQueue.main.async {
self.updateUI(with: processedData)
}
}
Вот честно, иногда этого DispatchQueue.main.async достаточно, чтобы чувствовать себя богом многопоточности. Но не всё так просто, ёпта.
2. Operation и OperationQueue А это уже надстройка над GCD для тех, кому мало просто «сделай где-нибудь». Тут уже можно строить цепочки: «сначала скачай, потом обработай, и только потом покажи». И отменять всё это дело одной кнопкой — красота!
let downloadOp = BlockOperation { /* Загрузка файла, который весит овердохуища */ }
let processOp = BlockOperation { /* Обработка, где всё может пойти по пизде */ }
// Вот это ключ! Сказали, что processOp — сын downloadOp. Пока папашка не закончит, сынок и пальцем не пошевелит.
processOp.addDependency(downloadOp)
let queue = OperationQueue()
queue.addOperations([downloadOp, processOp], waitUntilFinished: false) // И поехали!
Штука мощная, когда у тебя задачи зависят друг от друга, как пьяный друг от столба. Но писать её — тоже своего рода искусство, блядь.
3. Swift Concurrency (async/await, Actors) А это уже новое слово, прям свежак! Появилось в Swift 5.5, чтобы избавить нас от этого ада колбэков, где код превращается в лестницу в ад. Теперь можно писать почти как синхронный код, но чтобы он был асинхронным! Магия, сука!
// Объявляем функцию как async. Никаких completionHandler, нахуй!
func fetchUserData() async throws -> UserData {
// Просто ждём (await) ответ от сети. Никакой вложенности, всё ровно!
let data = try await networkService.request(.userProfile)
return try JSONDecoder().decode(UserData.self, from: data)
}
// Использование
Task { // Запускаем задачу
do {
let user = try await fetchUserData() // Ждём тут
// А чтобы ткнуть в UI — прыгаем на главный поток через MainActor
await MainActor.run {
self.user = user // Всё безопасно, UI не упадёт
}
} catch {
// Ну тут, понятно, если всё пошло нахуй
}
}
// А ещё есть Actors! Это такие хранители порядка, чтобы данные не выебали из разных потоков одновременно.
actor Counter {
private var value = 0
func increment() { value += 1 }
func getValue() -> Int { return value } // Доступ только через await, система сама очередь выстроит
}
Это, блядь, будущее. Код читается как книга, а не как шифровка параноика.
Так что же выбрать, ёпта?
- Swift Concurrency — если твой проект тянет iOS 13+ и ты не хочешь, чтобы потомки тебя проклинали. Бери это, не ошибёшься.
- GCD — для быстрых, простых выстрелов «сделай в фоне» или когда ковыряешься в старом коде, который видел виды.
- OperationQueue — когда у тебя настоящий пазл из задач, где одна в другую упирается, и нужно этим управлять как дирижёр оркестром, а не как обезьяна гранатой.
Вот и вся философия. Главное — не пытаться всё делать на главном потоке, а то пользователь подумает, что его телефон сдох, и выбросит его в хуй.