Расширенное использование AppState

August 26, 2025 · View on GitHub

Это руководство охватывает расширенные темы использования AppState, включая создание "точно в срок", предварительную загрузку зависимостей, эффективное управление состоянием и зависимостями, а также сравнение AppState с окружением SwiftUI.

1. Создание "точно в срок"

Значения AppState, такие как State, Dependency, StoredState и SyncState, создаются "точно в срок". Это означает, что они создаются только при первом доступе, что повышает эффективность и производительность вашего приложения.

Пример

extension Application {
    var defaultState: State<Int> {
        state(initial: 0) // Значение не создается, пока к нему не обратятся
    }
}

В этом примере defaultState не создается до тех пор, пока к нему не обратятся в первый раз, что оптимизирует использование ресурсов.

2. Предварительная загрузка зависимостей

В некоторых случаях вам может потребоваться предварительно загрузить определенные зависимости, чтобы убедиться, что они доступны при запуске вашего приложения. AppState предоставляет функцию load, которая предварительно загружает зависимости.

Пример

extension Application {
    var databaseClient: Dependency<DatabaseClient> {
        dependency(DatabaseClient())
    }
}

// Предварительная загрузка при инициализации приложения
Application.load(dependency: \.databaseClient)

В этом примере databaseClient предварительно загружается во время инициализации приложения, что гарантирует его доступность при необходимости в ваших представлениях.

3. Управление состоянием и зависимостями

3.1 Общее состояние и зависимости в приложении

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

Пример

private extension Application {
    var stateValue: State<Int> {
        state(initial: 0, id: "stateValue")
    }

    var dependencyValue: Dependency<SomeType> {
        dependency(SomeType(), id: "dependencyValue")
    }
}

Это позволяет вам получить доступ к тому же State или Dependency в другом месте, используя тот же идентификатор.

private extension Application {
    var theSameStateValue: State<Int> {
        state(initial: 0, id: "stateValue")
    }

    var theSameDependencyValue: Dependency<SomeType> {
        dependency(SomeType(), id: "dependencyValue")
    }
}

Хотя этот подход является допустимым для совместного использования состояния и зависимостей в приложении путем повторного использования одного и того же строкового id, он, как правило, не рекомендуется. Он основан на ручном управлении этими строковыми идентификаторами, что может привести к:

  • Случайным коллизиям идентификаторов, если один и тот же идентификатор используется для разных предполагаемых состояний/зависимостей.
  • Трудности в отслеживании того, где определено состояние/зависимость, по сравнению с тем, где к нему осуществляется доступ.
  • Снижению ясности и поддерживаемости кода. initial значение, предоставленное в последующих определениях с тем же идентификатором, будет проигнорировано, если состояние/зависимость уже было инициализировано при первом доступе. Такое поведение является скорее побочным эффектом работы кэширования на основе идентификаторов в AppState, а не рекомендуемым основным шаблоном для определения общих данных. Предпочтительнее определять состояния и зависимости как уникальные вычисляемые свойства в расширениях Application (которые автоматически генерируют уникальные внутренние идентификаторы, если явный id не предоставлен фабричному методу).

3.2 Ограниченный доступ к состоянию и зависимостям

Чтобы ограничить доступ, используйте уникальный идентификатор, такой как UUID, чтобы гарантировать, что только нужные части приложения могут получить доступ к определенным состояниям или зависимостям.

Пример

private extension Application {
    var restrictedState: State<Int?> {
        state(initial: nil, id: UUID().uuidString)
    }

    var restrictedDependency: Dependency<SomeType> {
        dependency(SomeType(), id: UUID().uuidString)
    }
}

3.3 Уникальные идентификаторы для состояний и зависимостей

Когда идентификатор не предоставляется, AppState генерирует идентификатор по умолчанию на основе местоположения в исходном коде. Это гарантирует, что каждый State или Dependency является уникальным и защищен от непреднамеренного доступа.

Пример

extension Application {
    var defaultState: State<Int> {
        state(initial: 0) // AppState генерирует уникальный идентификатор
    }

    var defaultDependency: Dependency<SomeType> {
        dependency(SomeType()) // AppState генерирует уникальный идентификатор
    }
}

3.4 Доступ к состоянию и зависимостям на уровне файла

Для еще более ограниченного доступа в пределах одного и того же файла Swift используйте уровень доступа fileprivate, чтобы защитить состояния и зависимости от внешнего доступа.

Пример

fileprivate extension Application {
    var fileprivateState: State<Int> {
        state(initial: 0)
    }

    var fileprivateDependency: Dependency<SomeType> {
        dependency(SomeType())
    }
}

3.5 Понимание механизма хранения AppState

AppState использует единый кэш для хранения State, Dependency, StoredState и SyncState. Это обеспечивает эффективное управление этими типами данных в вашем приложении.

По умолчанию AppState присваивает значение имени "App", что гарантирует, что все значения, связанные с модулем, привязаны к этому имени. Это усложняет доступ к этим состояниям и зависимостям из других модулей.

4. AppState по сравнению с окружением SwiftUI

AppState и окружение SwiftUI оба предлагают способы управления общим состоянием и зависимостями в вашем приложении, но они различаются по области применения, функциональности и вариантам использования.

4.1 Окружение SwiftUI

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

Преимущества:

  • Простота в использовании и хорошая интеграция с SwiftUI.
  • Идеально подходит для легковесных данных, которые необходимо совместно использовать в нескольких представлениях в иерархии.

Ограничения:

  • Данные доступны только в пределах определенной иерархии представлений. Доступ к тем же данным в разных иерархиях представлений невозможен без дополнительной работы.
  • Меньший контроль над поточно-безопасностью и персистентностью по сравнению с AppState.
  • Отсутствие встроенных механизмов персистентности или синхронизации.

4.2 AppState

AppState предоставляет более мощную и гибкую систему для управления состоянием во всем приложении с возможностями поточно-безопасности, персистентности и внедрения зависимостей.

Преимущества:

  • Централизованное управление состоянием, доступное во всем приложении, а не только в определенных иерархиях представлений.
  • Встроенные механизмы персистентности (StoredState, FileState и SyncState).
  • Гарантии типобезопасности и поточно-безопасности, обеспечивающие правильный доступ и изменение состояния.
  • Может обрабатывать более сложное управление состоянием и зависимостями.

Ограничения:

  • Требует больше настроек и конфигурации по сравнению с окружением SwiftUI.
  • Несколько менее интегрирован с SwiftUI по сравнению с Environment, хотя все еще хорошо работает в приложениях SwiftUI.

4.3 Когда что использовать

  • Используйте окружение SwiftUI, когда у вас есть простые данные, которые необходимо совместно использовать в иерархии представлений, например, настройки пользователя или предпочтения темы.
  • Используйте AppState, когда вам необходимо централизованное управление состоянием, персистентность или более сложное состояние, к которому необходимо получить доступ во всем приложении.

Заключение

Используя эти расширенные методы, такие как создание "точно в срок", предварительная загрузка, управление состоянием и зависимостями, а также понимание различий между AppState и окружением SwiftUI, вы можете создавать эффективные и ресурсосберегающие приложения с помощью AppState.


Этот перевод был сгенерирован автоматически и может содержать ошибки. Если вы носитель языка, мы будем признательны за ваши исправления через Pull Request.