Расширенное использование 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.