Однонаправленный поток данных
Все механизмы состояния складываются в единый принцип: данные текут в одну сторону — от источника истины к интерфейсу, а события идут обратно, меняя источник.
Суть урока: один источник истины, поток вниз к вью, события вверх к источнику. Этот цикл делает поведение приложения предсказуемым и отлаживаемым.
Соберём картину целиком. В SwiftUI данные движутся однонаправленно. Есть источник истины (@State или @Observable-модель). Из него данные текут вниз по дереву вью, формируя интерфейс. Когда пользователь что-то делает, вью отправляет событие наверх, которое меняет источник истины. И цикл повторяется — новое состояние рождает новый интерфейс.
+-----------------------------+
| ИСТОЧНИК ИСТИНЫ |
| @State / @Observable |
+-----------------------------+
| ^
данные | вниз вверх | событие
(состояние) (action)
v |
+-----------------------------+
| ВЬЮ (UI) |
| показывает состояние, |
| шлёт события по действиям |
+-----------------------------+Почему это важно? Потому что в любой момент состояние приложения полностью описывается источником истины. Чтобы понять, что на экране, достаточно посмотреть на данные. Нет скрытых изменений «где-то в обработчике». Это резко упрощает отладку: воспроизвели состояние — воспроизвели экран.
@Observable
class Counter { var value = 0 }
struct CounterScreen: View {
@State private var counter = Counter()
var body: some View {
VStack {
Text("\(counter.value)") // данные ВНИЗ
Button("+") { counter.value += 1 } // событие ВВЕРХ
}
}
}Попробуй сам ▶ — запусти код прямо в браузере (Pyodide). Здесь нет Swift, но логика та же, что под капотом мобильного кода:
# Цикл состояние -> вью -> событие -> новое состояние как редьюсер.
def reducer(state, action):
if action == 'increment':
return {'value': state['value'] + 1}
if action == 'reset':
return {'value': 0}
return state
def view(state): # данные текут вниз
return f"[ Счёт: {state['value']} ]"
state = {'value': 0}
print(view(state))
for action in ['increment', 'increment', 'reset', 'increment']:
state = reducer(state, action) # событие меняет источник истины
print(action, '->', view(state))Как работает под капотом
Однонаправленный поток — это не отдельный API, а следствие того, как устроены @State, @Binding и @Observable. Чтение свойства регистрирует зависимость, запись планирует перерисовку. Поскольку вью не хранят собственную «теневую» копию данных, а каждый раз выводят интерфейс из источника истины, рассинхронизация невозможна. Этот паттерн перекликается с архитектурами вроде Redux/TCA, но в SwiftUI он встроен в саму модель данных.
Частые ошибки
- Дублировать состояние. Локальная копия источника истины приводит к рассинхрону.
- Менять данные в обход потока. Прямые мутации вне реактивной системы интерфейс не обновят.
- Хранить производные данные. То, что вычисляется из состояния, лучше считать на лету (вычисляемое свойство).
Best practices
- Держите единственный источник истины для каждой единицы данных.
- Производные значения вычисляйте, а не дублируйте.
- Думайте циклом: состояние → интерфейс → событие → новое состояние.
Итоги. Однонаправленный поток данных связывает @State, @Binding и @Observable в стройную систему: один источник истины, данные вниз, события вверх. Этот принцип делает SwiftUI-приложения предсказуемыми и легко отлаживаемыми.
Шире контекста
Однонаправленный поток данных — это не изобретение SwiftUI, а проверенный индустрией паттерн, знакомый по архитектурам Redux в вебе и The Composable Architecture в мире Swift. Его сила в предсказуемости: раз состояние приложения целиком описывается источником истины, любой баг воспроизводится воспроизведением состояния, а не охотой за скрытыми мутациями в разрозненных обработчиках. Это резко упрощает и отладку, и тестирование, и совместную работу в команде. Производные данные в этой модели не хранят, а вычисляют на лету через вычисляемые свойства — так исключается рассинхронизация между «исходником» и «копией». По мере роста приложения вы, возможно, придёте к более формальным архитектурам со слоем редьюсеров и явными действиями, но фундамент везде один: единый источник истины, данные вниз, события вверх. Усвоив этот цикл сейчас, на маленьких примерах, вы заложите мышление, которое масштабируется на приложения любой сложности.