Практика: AsyncSequence
В этой главе мы разберем технологию AsyncSequence
в Swift, которая позволяет работать с последовательностями данных асинхронно. AsyncSequence полезен, когда нам нужно получать данные постепенно или по частям, например, при чтении из потока данных или получении событий. Мы рассмотрим реальные примеры использования и узнаем, как управлять асинхронными последовательностями.
Что такое AsyncSequence?
AsyncSequence
— это протокол, который предоставляет интерфейс для асинхронного итератора. Вместо того чтобы возвращать все элементы сразу, как обычные последовательности Sequence
, AsyncSequence
возвращает элементы по одному, позволяя обрабатывать их асинхронно.
Это особенно полезно для работы с операциями, которые могут занять неопределенное время, например:
- Сетевые запросы с постепенным поступлением данных.
- Потоки данных, такие как события или сообщения.
- Чтение файлов или данных из внешних источников.
Основные концепции
AsyncIterator
— объект, который итерирует через элементы асинхронной последовательности.for await
— специальная конструкция для итерации по элементам AsyncSequence.
Network status
Давайте рассмотрим простой пример асинхронной последовательности, которая используется для отслеживания статуса сети в реальном времени. Этот подход позволяет нам удобно и эффективно обрабатывать изменения в статусе интернет-соединения.
extension NWPath.Status {
var isConnected: Bool {
self != .satisfied
}
}
struct NetworkStatus: AsyncSequence {
typealias Element = Bool
func makeAsyncIterator() -> AsyncStream<Element>.Iterator {
let monitor = NWPathMonitor()
let monitorQueue = DispatchQueue(label: String(describing: Self.self) + "Queue")
return AsyncStream { continuation in
monitor.pathUpdateHandler = { path in
continuation.yield(path.status.isConnected)
}
monitor.start(queue: monitorQueue)
continuation.onTermination = { @Sendable _ in
monitor.cancel()
}
}
.makeAsyncIterator()
}
}
-
NetworkStatus
реализует протокол AsyncSequence. ПротоколAsyncSequence
требует реализации типа алиасаElement
(является типом данныхBool
) и методmakeAsyncIterator()
. Последний возвращает асинхронный итератор, который будет управлять последовательностью значений. -
В основе нашего подхода лежит
NWPathMonitor
из фреймворкаNetwork
, который предназначен для отслеживания статуса сети. Этот монитор позволяет следить за изменениями подключения, включая переключения между Wi-Fi, сотовой связью и отсутствием сети.
monitor.pathUpdateHandler
: данный обработчик вызывается каждый раз, когда происходит изменение состояния сети. Мы используем его, чтобы передать новое значение состояния черезcontinuation.yield
.monitor.start(queue:)
: для запускаNWPathMonitor
необходимо указать, в каком потоке (очереди) будет обрабатываться его работа. Здесь используется очередьDispatchQueue
, специально созданная для мониторинга.
- Асинхронные последовательности (sequence), такие как
AsyncStream
, обеспечивают удобный способ создания и управления последовательными данными, которые асинхронно поступают во времени. В нашем кодеAsyncStream
создаёт поток значений на основе изменений статуса сети. Этот поток затем возвращает итератор, который мы передаём дальше.
continuation.yield
: передаёт данные (в данном случае — состояние сети) асинхронно в поток, когда изменяется статус сети.continuation.onTermination
: обрабатывает завершение потока. Когда поток завершён, монитор сетиNWPathMonitor
останавливается с помощью методаcancel()
.
Использование
Используя асинхронный цикл for await
, мы можем последовательно получать значения состояния сети. Этот цикл будет постоянно ждать изменения состояния и реагировать на него.
var isNetworkAvailable: Bool = false
for await networkAlive in NetworkStatus() {
isNetworkAvailable = networkAlive
}