← Назад к вопросам

Как работает async/await в Swift?

2.8 Senior🔥 101 комментариев
#CI/CD и инструменты разработки#Soft Skills и карьера#SwiftUI

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает async/await в Swift?

Async/await — это модель асинхронного программирования, представленная в Swift 5.5, которая позволяет писать асинхронный код в последовательном, легко читаемом стиле, избегая "ада обратных вызовов" (callback hell) и сложностей с цепочками завершения (completion handlers).

Основные концепции

1. Async-функции

Функция объявляется как асинхронная с ключевым словом async после её параметров. Такая функция может приостанавливать своё выполнение в определённых точках.

func fetchUserData() async throws -> User {
    // Асинхронная операция
}

2. Await-выражения

Ключевое слово await используется для вызова асинхронной функции и указывает точку, где выполнение может быть приостановлено. Важно: await не блокирует поток, а позволяет системе переключиться на другую задачу.

let user = try await fetchUserData()

Как это работает под капотом

Континуации (Continuations)

Когда компилятор встречает await, он разбивает функцию на части:

  • До await — код выполняется синхронно
  • В точке await — создаётся континуация (состояние функции: локальные переменные, точка остановки)
  • После await — выполнение возобновляется, когда результат готов

Swift автоматически управляет сохранением и восстановлением состояния функции.

Кооперативная отмена задач

Async/await построен на системе кооперативной отмены:

  • Задачи могут быть отменены
  • Асинхронные функции должны периодически проверять отмену
  • Отмена распространяется по иерархии задач
func processData() async {
    // Проверка отмены задачи
    try Task.checkCancellation()
    
    // Или проверка через свойство
    if Task.isCancelled {
        return
    }
}

Структурный параллелизм

Swift реализует структурный параллелизм, где время жизни асинхронных задач привязано к области видимости:

Параллельное выполнение

async let firstImage = downloadImage(url1)
async let secondImage = downloadImage(url2)

let images = await [firstImage, secondImage] // Ожидание обеих задач

Асинхронные последовательности

for await line in file.lines {
    process(line)
}

Task и TaskGroup

Task — базовая единица асинхронной работы

Task {
    let result = await calculateSomething()
    await MainActor.run {
        updateUI(with: result)
    }
}

TaskGroup — для группы параллельных задач

func downloadAllImages(urls: [URL]) async throws -> [UIImage] {
    try await withThrowingTaskGroup(of: UIImage.self) { group in
        for url in urls {
            group.addTask {
                try await downloadImage(from: url)
            }
        }
        
        var images: [UIImage] = []
        for try await image in group {
            images.append(image)
        }
        return images
    }
}

Акторы (Actors)

Акторы — это тип, обеспечивающий безопасный доступ к состоянию в асинхронном коде через механизм изоляции:

actor Counter {
    private var value = 0
    
    func increment() {
        value += 1
    }
    
    func getValue() -> Int {
        return value
    }
}

// Использование
let counter = Counter()
await counter.increment()
let value = await counter.getValue()

Практические преимущества

  1. Улучшенная читаемость — код выглядит как синхронный
  2. Упрощение обработки ошибок — используется привычный try/catch
  3. Автоматическое управление памятью — нет утечек в замыканиях
  4. Интеграция с существующим кодом — можно оборачивать callback-функции в async-интерфейс
  5. Производительность — меньше накладных расходов по сравнению с DispatchQueue

Пример полного цикла

struct DataLoader {
    func loadData() async throws -> Data {
        // Асинхронный сетевой запрос
        let (data, _) = try await URLSession.shared.data(from: url)
        return data
    }
    
    func processInParallel() async throws -> [ProcessedData] {
        async let firstTask = processDataPart1()
        async let secondTask = processDataPart2()
        
        let results = await try [firstTask, secondTask]
        return results
    }
}

// Использование
Task {
    do {
        let loader = DataLoader()
        let data = try await loader.loadData()
        let processed = try await loader.processInParallel()
        await updateUI(with: processed)
    } catch {
        handleError(error)
    }
}

Async/await в Swift представляет собой фундаментальный сдвиг в асинхронном программировании, предлагая разработчикам выразительный, безопасный и производительный способ работы с асинхронными операциями, сохраняя при этом сильную типизацию и современные возможности языка.