SwiftUI - 数据
在为 Apple 平台开发响应式和交互式应用程序时,数据管理是一个非常重要且关键的部分。众所周知,SwiftUI 使用声明式方式,应用程序的 UI 将根据底层数据自动更新,因此无论何时数据由于某些外部事件或用户操作而发生变化,它都会直接影响界面的各个部分。
因此,数据及其流和状态的管理非常重要。该框架提供了各种工具,例如状态变量和绑定,以将数据连接到应用程序的 UI。这些工具管理数据的来源或数据中发生的任何变化。以下是 SwiftUI 中最常用的数据管理技术 −
@State 属性包装器
@Binding 属性包装器
@ObservedObject 属性包装器
@EnvironmentObject 属性包装器
SwiftUI 中的 @State 属性包装器
@State 属性包装器用于读取和写入由 SwiftUI 管理的值。它为我们存储在视图中的给定值类型保存单一来源。它可以通过使用 @State 属性为所有类型的视图创建状态变量,并且每个状态变量都用某个初始值初始化。
因此,当状态变量的值发生变化时,SwiftUI 将自动更新视图中依赖于状态变量值的那些部分。状态变量通常被声明为私有的,这可以防止它们在范围之外使用。
我们可以改变状态属性。如果我们将状态属性传递给子视图,SwiftUI 将在主容器视图中的值发生变化时更新子视图,而子视图不能修改该值。要修改该值,我们需要将其作为绑定传递。我们也可以在 State 中存储 Observable()。
语法
以下是语法 −
@State private var value : Double = 2.3
示例
以下 SwiftUI 程序创建并访问状态变量。在这里,状态管理计数变量的值,每当计数的值发生变化时,视图都会相应更新。
import SwiftUI struct ContentView: View { // State variable @State private var count = 0 var body: some View { VStack { Text("Counter: \(count)").font(.largeTitle) Button("Increment") { count += 1 } .frame(width: 100, height: 60) .background(.blue) .foregroundStyle(.white) .font(.headline) } } } #Preview { ContentView() }
输出

SwiftUI 中的 @Binding 属性包装器
绑定属性包装器在子视图和父视图之间创建双向关系,以便子视图可以轻松读取和写入父视图数据,反之亦然。
在这里,我们可以根据需要随时更新绑定变量,而无需直接将数据存储在其中。要传递绑定属性包装器,我们需要在属性前使用 $。或者我们可以说,我们可以借助绑定属性包装器将状态属性传递给另一个视图。我们还可以使用 @Binding 属性包装器创建绑定属性。
语法
以下是语法−
@Binding var value : Bool
示例
以下 SwiftUI 程序创建绑定属性。在这里,我们将状态变量作为绑定传递并创建了一个绑定变量。
import SwiftUI struct ContentView: View { // state variable @State private var count = 0 var body: some View { VStack { Text("Counter: \(count)").font(.largeTitle).border(.black, width: 4) // Passing count as a binding newView(count: $count) } } } struct newView: View { // Binding variable @Binding var count: Int var body: some View { Button("Increase Value") { count += 1 } .frame(width: 130, height: 50) .background(.brown) .foregroundStyle(.white) .font(.headline) } } #Preview { ContentView() }
输出

SwiftUI 中的 @StateObject 和 @ObservedObject 属性包装器
@ObservedObject 属性包装器用于包装可观察对象并观察它们,而 @StateObject 用于创建和管理可观察对象。这两个包装器都需要符合 ObservableObject 协议的对象。
因此,每当可观察对象的值发生修改时,SwiftUI 都会更新与该对象相关的所有视图。它不包含任何默认值或初始值,可以由子视图使用。这里允许子视图更新属性。
语法
以下是语法−
@StateObject private var model = ObservableObject() @ObservedObject private var model = ObservableObject()
示例
以下 SwiftUI 程序使用 @StateObject 和 @ObservedObject 属性来管理可观察对象。
import SwiftUI // 创建可观察对象 class Counter: ObservableObject { @Published var count = 0 } struct ContentView: View { @StateObject private var counter = Counter() var body: some View { // 将计数器传递给 newView newView(myCounter: counter) } } struct newView: View { // Observing the model @ObservedObject var myCounter: Counter var body: some View { VStack { Text("Count: \(myCounter.count)") .font(.largeTitle) .bold() .padding() Button("Increment") { myCounter.count += 1 } .frame(width: 130, height: 50) .background(.brown) .foregroundStyle(.white) .font(.headline) } } } #Preview { ContentView() }
输出

SwiftUI 中的 @EnvironmentObject 属性包装器
@EnvironmentObject 属性包装器用于在具有可观察对象的所有视图之间共享数据。它共享数据而无需在视图层次结构中明确传递数据。数据在层次结构中的所有视图的公共环境中共享,如果任何视图更新数据,则它将自动更新所有视图。
共享对象必须符合 ObservableObject 协议,并且其属性必须使用 @Published 定义。共享数据必须在视图层次结构的较高级别的 .environmentObject() 中注入,并且可以使用 @EnvironmentObject 由任何视图访问。
语法
以下是语法 −
@EnvironmentObject var mySettings: ObservableObject()
示例
以下 SwiftUI 程序使用 @EnvironmentObject 设置 dark 模式。
import SwiftUI class Settings: ObservableObject { @Published var darkMode: Bool = false } struct ContentView: View { @StateObject private var newSettings = Settings() var body: some View { VStack { Text("Original View") .font(.largeTitle) .padding() // Toggle dark mode ToggleView() // Display dark mode DisplayView() } // 在环境对象中传递 newSettings .environmentObject(newSettings) } } struct ToggleView: View { // Accessing the Settings @EnvironmentObject var mySettings: Settings var body: some View { // Binding darkMode to the toggle Toggle("Dark Mode", isOn: $mySettings.darkMode) .padding() .frame(width: 200, height: 200) .background(mySettings.darkMode ? .black : .white) .foregroundStyle(mySettings.darkMode ? .white : .black) } } struct DisplayView: View { // Access the Settings @EnvironmentObject var settings: Settings var body: some View { Text("Dark Mode is \(settings.darkMode ? "Activated" : "Deactivated")") .font(.title) .padding() .foregroundStyle(settings.darkMode ? .white : .black) .background(settings.darkMode ? .black : .white) } } #Preview { ContentView() }
输出
