Программирование
Стриминг изменений с помощью Observations
Появление типа Observations знаменует собой значительное улучшение возможностей Swift по наблюдению за данными, особенно для разработчиков, использующих Swift Concurrency.
Несколько лет назад Apple представила фреймворк Observation. Он стал основным инструментом для построения наблюдаемых моделей, заменив Combine. На этой неделе мы расскажем о новой части фреймворка под названием Observations.
Основным недостатком фреймворка Observation была его неспособность преобразовывать наблюдаемые типы в асинхронные потоки, что позволяло бы нам наблюдать за ними так же, как мы это делаем с Publisher в Combine.
func startObservation() {
withObservationTracking {
render(store.state)
} onChange: {
Task { startObservation() }
}
}
Хотя фреймворк Observation предлагает функцию withObservationTracking, которая позволяет нам вручную отслеживать изменения в наблюдаемом типе, он все еще имеет некоторые ограничения.
Во-первых, рекурсивное наблюдение приходится инициировать вручную, поскольку оно срабатывает только при первом изменении. Во-вторых, оно не вписывается в мир Swift Concurrency, поскольку его нельзя использовать как асинхронный поток внутри асинхронного цикла for. К счастью, Apple исправила все эти недостатки, представив новый тип Observations. Он предназначен для работы в паре с макросом Observable.
let store = Store() // Observable
struct State {
let items: [String]
let isLoading: Bool
}
let streamOfStates = Observations {
let state = State(
items: store.items,
isLoading: store.isLoading
)
return state
}
for await state in streamOfStates {
render(state)
}
Тип Observations соответствует протоколу AsyncSequence, что позволяет использовать экземпляры этого типа внутри асинхронного цикла for. Замыкание, которое мы используем для инициализации экземпляра типа Observations, неявно отслеживает все свойства наблюдаемых экземпляров, с которыми вы работаете.
Как видно из примера ниже, мы создаём новое состояние внутри замыкания. Мы работаем со свойствами items и isLoading типа Store, соответствующего протоколу Observable.
Мы наблюдаем за создаваемыми экземплярами типа State внутри асинхронного цикла for. При каждом изменении свойств items и isLoading он создаёт новый экземпляр типа State, который мы асинхронно извлекаем внутри цикла.
Тип Observations достаточно интеллектуален для использования транзакционных обновлений, что означает, что он не генерирует значение для каждого изменения. Он может группировать обновления, когда изменения происходят одновременно в свойствах items и isLoading.
extension Observable {
func stream<Value: Sendable>(
of keyPath: KeyPath<Self, Value>
) -> any AsyncSequence<Value, Never> {
Observations {
self[keyPath: keyPath]
}
}
}
Вот небольшое расширение протокола Observable, позволяющее вам легко создавать асинхронные последовательности для KeyPath для наблюдаемого типа.
for await items in store.stream(of: \.items) {
print(items)
}
Появление типа Observations знаменует собой значительное улучшение возможностей Swift по наблюдению за данными, особенно для разработчиков, использующих Swift Concurrency. Он стирает разрыв между реактивными обновлениями и современными асинхронными шаблонами, упрощая создание понятных, эффективных и отзывчивых пользовательских интерфейсов. Надеюсь, вам понравится эта публикация. Подписывайтесь на автора в Твиттере и задавайте вопросы по теме. Спасибо за прочтение, увидимся на следующей неделе!
-
Видео и подкасты для разработчиков3 недели назад
Разработка видеоредактора
-
Новости4 недели назад
Видео и подкасты о мобильной разработке 2025.50
-
Вовлечение пользователей2 недели назад
Инженерия уверенности: почему ваш онбординг, вероятно, слишком короткий
-
Видео и подкасты для разработчиков2 недели назад
От идеи к CVE: как находить уязвимости в Android

