Swift Academy · Урок

Хранилище и интеграция со SwiftUI

Управляйте представлениями из хранилища TCA.

Урок 2 из 413 шагов

«Хранилище и интеграция со SwiftUI» — бесплатный урок Swift Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.

Что такое хранилище

Хранилище — это объект времени выполнения, который содержит состояние компонента и запускает его редуктор. Представление SwiftUI наблюдает за хранилищем, чтобы читать состояние, и отправляет ему действия для запуска изменений.

Хранилище служит связующим звеном между чистой логикой редуктора и работающим интерактивным интерфейсом.

import ComposableArchitecture
import SwiftUI

// A Store holds State, runs the Reducer,
// and is observed by SwiftUI views.

Псевдоним типа StoreOf

StoreOf<Feature> — это удобный псевдоним для хранилища, специализированного под типы состояния и действий компонента. Обычно представление хранит такое хранилище в качестве сохранённого свойства.

Таким образом, представление счётчика хранит StoreOf<CounterFeature>.

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        Text("Count: \(store.count)")
    }
}

Создание хранилища

Хранилище создаётся с помощью инициализатора Store, которому передаются начальное состояние и запускаемый редуктор. Обычно это делают один раз рядом с точкой входа приложения.

Замыкающий блок возвращает экземпляр компонента.

import ComposableArchitecture
import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            CounterView(
                store: Store(initialState: CounterFeature.State()) {
                    CounterFeature()
                }
            )
        }
    }
}

Прямое чтение состояния

При использовании современного наблюдения представление читает состояние непосредственно из хранилища с помощью точечной нотации, например store.count. Поскольку состояние отмечено как @ObservableState, SwiftUI повторно отображает только те части, которые зависят от изменившихся значений.

Для простого чтения дополнительная оболочка не требуется.

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        VStack {
            Text("Count: \(store.count)")
        }
    }
}

Отправка действий

Чтобы изменить состояние, представление отправляет действие с помощью store.send(.someAction). Хранилище передаёт действие редуктору, который изменяет состояние и может запускать эффекты.

В этом примере кнопки отправляют действия увеличения и уменьшения.

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        HStack {
            Button("-") { store.send(.decrementTapped) }
            Text("\(store.count)")
            Button("+") { store.send(.incrementTapped) }
        }
    }
}

Привязки из хранилища

Для элементов управления SwiftUI, которым нужны двусторонние привязки, TCA позволяет получить Binding из хранилища, если состояние использует действия с привязками. Элемент управления обновляет состояние, отправляя действие привязки.

Здесь TextField связан с полем имени.

import ComposableArchitecture
import SwiftUI

struct FormView: View {
    @Bindable var store: StoreOf<FormFeature>
    var body: some View {
        TextField("Name", text: $store.name)
    }
}

Устаревший WithViewStore

До появления наблюдения представления оборачивали свой интерфейс в WithViewStore, чтобы читать состояние и получать viewStore для отправки действий. Вы всё ещё встретите такой подход в старом коде.

Замыкание observe выбирает состояние, от которого зависит представление.

import ComposableArchitecture
import SwiftUI

struct LegacyCounter: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        WithViewStore(store, observe: { $0 }) { viewStore in
            Text("Count: \(viewStore.count)")
        }
    }
}

Выбор наблюдаемых данных

В устаревшем стиле замыкание observe сужает область состояния, за которой наблюдает представление, поэтому оно повторно отображается только при изменении этих значений. Наблюдать за всем состоянием проще всего; наблюдение за его частью оптимизирует большие представления.

Современный @ObservableState выполняет это автоматически, но понимание observe помогает при чтении старого кода.

import ComposableArchitecture
import SwiftUI

// Observe just the count to limit re-renders:
WithViewStore(store, observe: { $0.count }) { viewStore in
    Text("\(viewStore)")
}

Отправка действий с данными

Действия с ассоциированными значениями отправляют, передавая это значение. Так представление передаёт пользовательский ввод, необходимый редуктору.

Здесь выбор строки отправляет выбранный идентификатор.

import ComposableArchitecture
import SwiftUI

struct ListView: View {
    let store: StoreOf<ListFeature>
    var body: some View {
        Button("Pick 42") {
            store.send(.rowSelected(id: 42))
        }
    }
}

Анимация действий

К отправленному действию можно прикрепить анимацию, чтобы результирующее изменение состояния было анимировано. Передайте аргумент animation в send.

Так вопросы анимации остаются в месте вызова, а состояние сохраняется в виде обычных данных.

import ComposableArchitecture
import SwiftUI

Button("Toggle") {
    store.send(.toggleTapped, animation: .default)
}

Сборка представления

Полное представление TCA содержит StoreOf, читает состояние с помощью точечной нотации и отправляет действия из элементов управления. Остальное делает редуктор, сохраняя представление лаконичным и декларативным.

Именно такое разделение делает представления TCA простыми для чтения и предварительного просмотра.

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        VStack {
            Text("Count: \(store.count)")
            Button("Increment") { store.send(.incrementTapped) }
        }
    }
}

Быстрая проверка: управление интерфейсом

Вспомните, как представление SwiftUI запускает изменение состояния в TCA.

Итоги: хранилище и SwiftUI

Вы подключили компонент к SwiftUI:

  • StoreOf<Feature> хранит состояние и запускает редуктор.
  • Хранилище создаётся с начальным состоянием и редуктором компонента.
  • Современное наблюдение позволяет читать состояние с помощью точечной нотации, например store.count.
  • Представления изменяют состояние, вызывая store.send(.action), при необходимости с данными или анимацией.
  • Устаревшие WithViewStore и его замыкание observe встречаются в старом коде.

Далее вы добавите в редуктор побочные эффекты и внедряемые зависимости.

import ComposableArchitecture
import SwiftUI

// Recap: StoreOf holds state, view reads with dot syntax,
// store.send(.action) drives every change.
Можно начать бесплатно

Изучай Swift с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
122
Уроки
409

Часто задаваемые вопросы

Урок «Хранилище и интеграция со SwiftUI» бесплатный?

Да — полный текст урока «Хранилище и интеграция со SwiftUI» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.

Чему я научусь в уроке «Хранилище и интеграция со SwiftUI»?

Управляйте представлениями из хранилища TCA. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Хранилище и интеграция со SwiftUI»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Состояние, действие и редьюсер
  2. Хранилище и интеграция со SwiftUI
  3. Эффекты и зависимости
  4. Композиция и тестирование возможностей
← Назад к Swift Academy