Можно ли вызывать async-функцию внутри другого метода в Swift?

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

Ответ

Да, асинхронную (async) функцию можно вызывать внутри другого метода, но только если вызывающий контекст также является асинхронным. Для вызова из синхронного контекста необходимо использовать Task.

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

func fetchUserData() async throws -> Data {
    // ... асинхронная логика
}

func processAndDisplayUser() async {
    do {
        // Прямой вызов, так как контекст async
        let data = try await fetchUserData()
        await MainActor.run { /* обновить UI */ }
    } catch {
        print("Failed: (error)")
    }
}

2. Вызов из синхронного контекста (например, кнопки UI):

Button("Load Data") {
    // Запускаем асинхронную работу в отдельной Task
    Task {
        do {
            let data = try await fetchUserData()
            // Обновление UI должно происходить на главном акторе
            await MainActor.run { self.data = data }
        } catch {
            // Обработка ошибок
        }
    }
}

3. Структурированный параллелизм с async let:

func loadDashboard() async throws -> Dashboard {
    // Параллельное выполнение нескольких async-вызовов
    async let user = fetchUserProfile()
    async let news = fetchLatestNews()
    async let stats = fetchUserStats()

    // Ожидание всех результатов
    return try await Dashboard(user: user, news: news, stats: stats)
}

Ключевые правила:

  • Используйте await для приостановки текущего потока без его блокировки.
  • Всегда обрабатывайте потенциальные ошибки (try/catch).
  • Для обновления пользовательского интерфейса после асинхронной работы переключайтесь на MainActor.
  • Избегайте создания неструктурированных задач (Task.detached) без необходимости.