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()
}
输出

