Пишу простым языком об iOS разработке на Swift и мобильной разработке в целом.
Обо мне: https://t.me/hardworkerIT/3
Чат: @hardworkerChatIT
Канал про разработку и жизнь в ИТ: @itDenisov
Вакансии по мобильной разработке: @mobileDevJobs
Post #276
1.22K
🔢 Мост между эпохами: как превратить completion handlers в современный async/await.
Swift Concurrency с async/await стал стандартом современной iOS-разработки, но вокруг нас все еще живут тонны кода, написанного на completion handlers. Вместо болезненного рефакторинга всего легаси можно построить элегантный мост между старым и новым кодом. Сегодня разберем, как превратить старый код с устаревшим подходом в красивые async-функции.
Два разных мира асинхронности:
Представьте ситуацию: вы пишете современное приложение на Swift Concurrency, но вам нужно использовать библиотеку или системный API, который работает через completion handlers:
Решение - Continuations переводчики между эпохами:
Swift предоставляет специальные функции-континуации, которые становятся мостом между двумя моделями:
Типы континуаций и когда что использовать:
Swift предлагает четыре варианта, каждый для своего случая:
🔵withCheckedContinuation - для API, которые всегда возвращают результат.
🔵withCheckedThrowingContinuation - для API, которые могут завершиться ошибкой.
🔵withUnsafeContinuation и withUnsafeThrowingContinuation - для оптимизации производительности.
Ключевое правило: вызывать resume только один раз.
Самая частая ошибка при работе с континуациями: множественный вызов resume(). Checked-версии помогут отловить это в рантайме:
Производительность: Checked vs Unsafe.
🔵Checked continuations добавляют runtime-проверки на двойной вызов resume() - безопаснее, но чуть медленнее.
🔵Unsafe continuations убирают проверки - быстрее, но требуют абсолютной уверенности в корректности кода.
🔗 Ссылка на подробную статью
💡 Вывод:
Continuation - это не просто синтаксический сахар, а мощный инструмент для постепенной миграции на Swift Concurrency. Они открывают возможность интегрировать легаси-код в современную асинхронную архитектуру, создавать удобные async-интерфейсы для API, работающих через колбэки и контролировать процесс миграции, не переписывая все и сразу.
➡️ Подписаться на канал
Мобильный трудоголик
Swift Concurrency с async/await стал стандартом современной iOS-разработки, но вокруг нас все еще живут тонны кода, написанного на completion handlers. Вместо болезненного рефакторинга всего легаси можно построить элегантный мост между старым и новым кодом. Сегодня разберем, как превратить старый код с устаревшим подходом в красивые async-функции.
Два разных мира асинхронности:
Представьте ситуацию: вы пишете современное приложение на Swift Concurrency, но вам нужно использовать библиотеку или системный API, который работает через completion handlers:
// Старый код (до async/await)
func fetchUserData(userId: Int, completion: @escaping (Result<User, Error>) -> Void) {
// Некоторая асинхронная операция
NetworkService.shared.request(.user(id: userId)) { result in
completion(result)
}
}
// Как мы хотим использовать это в новом коде:
let user = try await fetchUserData(userId: 123)
Решение - Continuations переводчики между эпохами:
Swift предоставляет специальные функции-континуации, которые становятся мостом между двумя моделями:
// Новый async-интерфейс поверх старого API
func fetchUserData(userId: Int) async throws -> User {
return try await withCheckedThrowingContinuation { continuation in
// Вызываем старый метод с completion handler
fetchUserData(userId: userId) { result in
switch result {
case .success(let user):
// Пробуждаем async функцию с результатом
continuation.resume(returning: user)
case .failure(let error):
// Пробуждаем с ошибкой
continuation.resume(throwing: error)
}
}
}
}
Типы континуаций и когда что использовать:
Swift предлагает четыре варианта, каждый для своего случая:
🔵withCheckedContinuation - для API, которые всегда возвращают результат.
🔵withCheckedThrowingContinuation - для API, которые могут завершиться ошибкой.
🔵withUnsafeContinuation и withUnsafeThrowingContinuation - для оптимизации производительности.
Ключевое правило: вызывать resume только один раз.
Самая частая ошибка при работе с континуациями: множественный вызов resume(). Checked-версии помогут отловить это в рантайме:
// Опасный код (может вызвать краш)
func dangerousWrap() async -> String {
await withCheckedContinuation { continuation in
unreliableAPI { value in
continuation.resume(returning: value)
// Если API вызовет completion дважды — будет ошибка
}
}
}
// Безопасная обертка
func safeWrap() async -> String {
await withCheckedContinuation { continuation in
var hasResumed = false
unreliableAPI { value in
guard !hasResumed else { return }
hasResumed = true
continuation.resume(returning: value)
}
}
}
Производительность: Checked vs Unsafe.
🔵Checked continuations добавляют runtime-проверки на двойной вызов resume() - безопаснее, но чуть медленнее.
🔵Unsafe continuations убирают проверки - быстрее, но требуют абсолютной уверенности в корректности кода.
🔗 Ссылка на подробную статью
💡 Вывод:
Continuation - это не просто синтаксический сахар, а мощный инструмент для постепенной миграции на Swift Concurrency. Они открывают возможность интегрировать легаси-код в современную асинхронную архитектуру, создавать удобные async-интерфейсы для API, работающих через колбэки и контролировать процесс миграции, не переписывая все и сразу.
➡️ Подписаться на канал
Мобильный трудоголик
- 👍 8
- 🤝 5
- ❤ 2
- 🔥 1


