В каком контексте можно вызывать async/await методы в Swift?

«В каком контексте можно вызывать async/await методы в Swift?» — вопрос из категории Многопоточность, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Методы, помеченные async, можно вызывать только из асинхронного контекста с использованием ключевого слова await. Основные способы создания такого контекста:

1. Внутри другой async функции:

func fetchUserData() async throws -> User {
    // Вызов асинхронного метода с await
    let data = try await networkService.fetchData(from: url)
    return try JSONDecoder().decode(User.self, from: data)
}

2. В блоке Task: Это основной способ запуска асинхронного кода из синхронного контекста (например, из метода viewDidLoad).

// Запуск асинхронной задачи
Task {
    // Это асинхронный контекст
    let user = await fetchUserData()
    // Обновление UI должно быть на MainActor
    await MainActor.run {
        self.usernameLabel.text = user.name
    }
}

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

struct ContentView: View {
    @State private var data: String = ""

    var body: some View {
        Text(data)
            .task { // Асинхронный контекст, созданный SwiftUI
                data = await loadData()
            }
    }
}

Важные правила:

  • await не блокирует поток: Он приостанавливает выполнение текущей async функции, позволяя потоку выполнять другую работу, пока ожидается результат.
  • Вызов из синхронного контекста запрещен: Нельзя использовать await просто так. Нужно обернуть вызов в Task или находиться внутри async функции.
  • Обработка ошибок: Асинхронные функции, которые могут выбросить ошибку (throws), требуют использования try await.