В этой статье я объясню основные принципы комбинированной среды SwiftUI, используя простое приложение, которое меняет свое состояние в нескольких случаях.
Использование @State
В SwiftUI оболочка свойства @State
используется для объявления состояния представления. Когда состояние представления изменяется, платформа автоматически повторно отображает представление, чтобы отразить обновленное состояние. Это означает, что с помощью @State
вы можете создавать динамические интерактивные пользовательские интерфейсы, которые реагируют на пользовательский ввод и другие события.
Вот пример того, как @State
можно использовать в представлении SwiftUI:
struct ContentView: View { @State private var name = "John" var body: some View { VStack { Text("Hello, \(name)!") TextField("Enter your name", text: $name) } } }
Использование @Binding
Обертка свойства @Binding
используется для создания двусторонней привязки между состоянием представления и состоянием его родительского представления. Когда дочернее представление обновляет свое состояние с помощью свойства @Binding
, состояние родительского представления также обновляется, и наоборот. Это позволяет передавать данные из одного представления в другое таким образом, чтобы представления автоматически синхронизировались.
Вот пример того, как @Binding
можно использовать в иерархии представлений SwiftUI:
struct ParentView: View { @State private var name = "John" var body: some View { VStack { Text("Hello, \(name)!") ChildView(name: $name) } } } struct ChildView: View { @Binding var name: String var body: some View { TextField("Enter your name", text: $name) } }
В этом примере родительское представление имеет свойство состояния name
, объявленное с помощью оболочки свойства @State
. Дочернее представление ChildView
принимает состояние родителя name
в качестве свойства @Binding
. Когда пользователь вводит текстовое поле в дочернем представлении, свойство name
дочернего представления обновляется, что автоматически обновляет состояние name
родительского представления и повторно отображает оба представления. Это позволяет потоку данных между представлениями быть динамическим и синхронизированным.
Использование @StateObject
В SwiftUI оболочка свойства @StateObject
используется для объявления состояния представления, которым управляет класс, соответствующий протоколу ObservableObject
. Свойство @StateObject
автоматически синхронизируется с представлением, и представление будет автоматически обновляться при каждом изменении @StateObject
.
Протокол ObservableObject
позволяет вам определить класс, который может публиковать изменения своих свойств, которые затем могут наблюдаться представлением SwiftUI. Это упрощает управление сложным состоянием, которое необходимо разделить между несколькими представлениями.
Вот пример того, как @StateObject
можно использовать в представлении SwiftUI:
class User: ObservableObject { @Published var name = "John" } struct ContentView: View { @StateObject var user = User() var body: some View { VStack { Text("Hello, \(user.name)!") TextField("Enter your name", text: $user.name) } } }
В этом примере класс User
соответствует протоколу ObservableObject
и имеет свойство @Published
, name
, которое представляет собой данные, которые должны быть разделены между несколькими представлениями. Затем ContentView
использует оболочку свойства @StateObject
для объявления свойства состояния user
, которое является экземпляром класса User
. Всякий раз, когда пользователь вводит текстовое поле, свойство name
объекта состояния user
обновляется, что автоматически запускает повторную визуализацию представления.
Использование @EnvironmentObject
В SwiftUI оболочка свойства @EnvironmentObject
используется для доступа к общему состоянию из среды. Это способ передачи данных вниз по иерархии представлений без необходимости явно передавать их через несколько представлений. @EnvironmentObject
— это экземпляр класса, который соответствует протоколу ObservableObject
и объявлен в среде иерархии представлений с помощью метода .environmentObject()
.
Вот пример того, как @EnvironmentObject
можно использовать в иерархии представлений SwiftUI:
class UserSettings: ObservableObject { @Published var fontSize: CGFloat = 17 } struct ContentView: View { @EnvironmentObject var userSettings: UserSettings var body: some View { VStack { Text("Hello, World!") .font(.system(size: userSettings.fontSize)) SettingsView() } } } struct SettingsView: View { @EnvironmentObject var userSettings: UserSettings var body: some View { VStack { Text("Settings") Slider(value: $userSettings.fontSize, in: 10...20) } } }
В этом примере класс UserSettings
соответствует протоколу ObservableObject
и имеет свойство @Published
, fontSize
, которое представляет настройку пользователя. И ContentView
, и SettingsView
объявляют свойство @EnvironmentObject
userSettings
, которое ссылается на один и тот же экземпляр класса UserSettings
. Это означает, что оба представления имеют доступ к одному и тому же общему состоянию, и всякий раз, когда изменяется свойство fontSize
объекта userSettings
, оба представления будут автоматически обновляться, чтобы отразить это изменение.
Вы устанавливаете объект среды для иерархии представлений, используя метод .environmentObject()
в корневом представлении, например:
let userSettings = UserSettings() let contentView = ContentView() .environmentObject(userSettings)
Я надеюсь, что эта статья поможет, как всегда, весь код связан с моей страницей на github.