Ответ
async/await — это модель асинхронного программирования в Swift, которая позволяет писать последовательный, легко читаемый код для асинхронных операций, заменяя цепочки completion handlers ("callback hell").
Основные концепции:
async— ключевое слово, которым помечается асинхронная функция. Такая функция может быть приостановлена.await— ключевое слово, указывающее точку, где выполнение может быть приостановлено до завершения асинхронной операции. Поток при этом не блокируется.Task— единица работы, в которой выполняется асинхронный код.
Пример:
// Асинхронная функция для загрузки данных
func fetchUserData() async throws -> User {
let url = URL(string: "https://api.example.com/user")!
// `await` приостанавливает функцию, пока данные не будут загружены
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
// Вызов асинхронной функции
Task {
do {
let user = try await fetchUserData()
await MainActor.run {
// Обновление UI должно происходить на главном потоке
self.updateUI(with: user)
}
} catch {
print("Failed to fetch user: (error)")
}
}
Преимущества:
- Улучшенная читаемость: Код выглядит как синхронный.
- Упрощенная обработка ошибок: Используется привычный механизм
try/catch. - Безопасность: Компилятор помогает избежать распространенных ошибок (например, вызов асинхронного кода не из асинхронного контекста).
Важные нюансы:
- Нативно поддерживается с iOS 15, macOS 12, tvOS 15, watchOS 8.
- Для обратной совместимости с более старыми API используется
withCheckedContinuation. - Для работы с главным потоком используется
MainActor.
Ответ 18+ 🔞
Давай разберём эту штуку, которая всех так взбудоражила. async/await, блядь. Ну, наконец-то, ёпта! Вместо того чтобы писать эти ебуччие цепочки комплишн-хэндлеров, где к концу уже забываешь, что в начале делал, и код похож на лапшу, которую кот сука собака навертел.
В чём соль, блядь?
async— это как бирочка на функции: «Эй, я могу зависнуть, не жди меня тут, иди делай другие дела». Не блокирует поток, просто приостанавливается, хитрая жопа.await— это точка, где ты говоришь: «Ладно, я тут подожду, пока ты там своё дело сделаешь». Ключевое — поток-то не блокируется, система может в это время другую задачу пинать.Task— это типа контейнер, коробка, в которую ты эту асинхронную хуйню складываешь, чтобы она выполнялась.
Смотри, как это выглядит, без всей этой ебалы с колбэками:
// Функция, которая тащит данные из интернета
func fetchUserData() async throws -> User {
let url = URL(string: "https://api.example.com/user")!
// Вот тут `await` — стоп, пацаны, ждём ответа от сервака. Но система не тупит!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
// Как это вызвать
Task {
do {
// Красота же! Читается как обычный код. Никаких вложенных { } в { } в { }
let user = try await fetchUserData()
// А это чтобы на главный поток вернуться, UI обновить
await MainActor.run {
self.updateUI(with: user)
}
} catch {
print("Всё пропало, шеф: (error)") // Ошибки ловятся как у нормальных людей, try/catch
}
}
Почему это овердохуища?
- Читаемость, блядь! Смотришь на код и сразу понимаешь, что за чем идёт. Не нужно глазами прыгать по замыканиям.
- Ошибки теперь не нужно в десять разных мест пробрасывать — один
do/catchи делу конец. - Компилятор умный стал, он тебе подскажет, если ты попытаешься асинхронную хуйню из обычного места вызвать — сразу «чё за муда?».
Но есть подводные, блядь, камни:
- Работает нативно только с iOS 15, macOS 12 и так далее. Если нужно со старьём работать, придётся использовать
withCheckedContinuation— это такой костыль, но рабочий. - Чтобы тронуть UI, надо явно вернуться на главный поток через
MainActor. Не забывай, а то приложение рухнет, и будешь думать, что за пизда с ушами.
В общем, вещь нужная. Не панацея, конечно, но жить стало проще, волнение ебать упало.