Ответ
async/await — это модель асинхронного программирования в Swift, позволяющая писать асинхронный код в линейном, легко читаемом стиле, без цепочек completion handlers (callbacks).
Базовый пример сетевого запроса:
// 1. Объявление асинхронной функции
func fetchUserData(from url: URL) async throws -> User {
// 2. `await` приостанавливает функцию, пока не будет получен ответ,
// но не блокирует поток.
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw NetworkError.invalidResponse
}
// 3. Декодирование также может быть асинхронной операцией.
let user = try JSONDecoder().decode(User.self, from: data)
return user
}
// 4. Вызов асинхронной функции.
// Должен происходить внутри асинхронного контекста: `Task` или другой `async` функции.
Task {
do {
let url = URL(string: "https://api.example.com/user/1")!
let user = try await fetchUserData(from: url)
print("User received: (user.name)")
// 5. Обновление UI должно выполняться на главном потоке.
await MainActor.run {
self.nameLabel.text = user.name
}
} catch {
print("Failed to fetch user: (error)")
}
}
Пример параллельного выполнения запросов (Concurrency):
func fetchUserAndPosts(userId: Int) async throws -> (User, [Post]) {
async let user = fetchUserData(from: userURL) // Запускаем асинхронно
async let posts = fetchPostsData(from: postsURL) // Запускаем асинхронно
// Оба запроса выполняются параллельно.
// `try await` ожидает завершения обоих.
return try await (user, posts)
}
Ключевые концепции:
async— помечает функцию как асинхронную. Она может быть приостановлена.await— точка возможной приостановки, где функция ожидает результат асинхронной операции.Task— единица работы, которая выполняется асинхронно. Создает асинхронный контекст.throws— асинхронные функции могут выбрасывать ошибки, как и обычные.MainActor— глобальный актор, гарантирующий выполнение кода на главном потоке. Используется для обновления UI.
Ответ 18+ 🔞
Э, слушай, смотри, вот эта вся хуйня с async/await в Swift — это типа как взять свои старые кошмарные колбэки, которые в три этажа, и выкинуть их нахуй в окно. Вместо этого пишешь код, который выглядит почти как обычный, линейный, но при этом он нихуя не блокирует твой главный поток, пока там что-то грузится из интернета. Красота, ёпта!
Смотри, как это выглядит на практике, вот тебе классика жанра — запрос в сеть:
// 1. Вот объявляешь функцию и пишешь `async`. Это как знак "осторожно, тут можно вздремнуть".
func fetchUserData(from url: URL) async throws -> User {
// 2. А вот тут магия! `await` — это не блокировка, это вежливое "я подожду тут, на обочине, пока ты, URLSession, не притащишь мне данные".
// Поток в это время не стоит столбом, он может другим заняться. Умно, блядь.
let (data, response) = try await URLSession.shared.data(from: url)
// Ну тут обычная проверка, не обосрался ли запрос.
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw NetworkError.invalidResponse
}
// 3. Декодируем JSON. Тоже может быть асинхронным, если данных овердохуища.
let user = try JSONDecoder().decode(User.self, from: data)
return user
}
// 4. А теперь, чтобы эту красоту вызвать, нужен асинхронный контекст. Засовываем всё в `Task`.
Task {
do {
let url = URL(string: "https://api.example.com/user/1")!
// Ждём-с результат. Опять `await`.
let user = try await fetchUserData(from: url)
print("User received: (user.name)")
// 5. ВАЖНО! UI обновлять нужно на главном потоке. Для этого есть `MainActor`.
// Спрашиваешь у главного актора: "Браток, сделай мне одолжение, обнови label".
await MainActor.run {
self.nameLabel.text = user.name
}
} catch {
// Ну и если всё пошло по пизде, ловим ошибку.
print("Failed to fetch user: (error)")
}
}
А вот это вообще пиздец как удобно — запустить два запроса параллельно, а не ждать как лох по очереди:
func fetchUserAndPosts(userId: Int) async throws -> (User, [Post]) {
// Смотри, какая хитрая жопа! `async let` — это как сказать: "Эй, чувак, начинай качать юзера, а ты, второй чувак, начинай качать посты. Работайте!"
async let user = fetchUserData(from: userURL)
async let posts = fetchPostsData(from: postsURL)
// А тут мы просто ждём, пока оба этих молодца закончат. Они работают одновременно, ёба!
return try await (user, posts)
}
Короче, основные плюшки, чтобы не быть мудаком:
async— клеймо на функции. Говорит: "Внутри меня может бытьawait, я умею засыпать и просыпаться".await— точка, где твоя функция говорит "я тут постою, подожду результата, не мешайте". Это НЕ БЛОКИРОВКА потока, запомни, ебать!Task— это как коробка, в которую ты засовываешь асинхронную работу, чтобы она вообще запустилась.throws— да, асинхронные функции тоже могут выбросить тебе ошибку в ебло, если что-то пойдёт не так.MainActor— твой главный по тарелочкам. Гарантирует, что всё, что внутриrun, выполнится на главном потоке. Без него лезть в UI из асинхронного кода — это прямой путь в крематорий для приложения.