基础#
在 SwiftUI 中,@ObservedObject 和 @StateObject 都是用于管理视图中对象状态的属性包装器。
@ObservedObject 用于标记 ObservableObject 协议的对象为当前视图观察的对象。这意味着当被 @ObservableObject 标记的对象的状态发生变化时,视图会自动刷新。通常,@ObservedObject 用于在视图之间共享状态。
例如,假设有一个符合 ObservableObject 协议的 UserSettings 类,用于存储用户偏好设置。
class UserSettings: ObservableObject {
@Published var theme: Theme = .light
}
我们可以在视图中使用 @ObservedObject 属性包装器来观察 UserSetting 对象,如下所示:
struct SettingsView: View {
@ObservedObject var userSettings = UserSettings()
var body: some View {
// ...
}
}
在这个例子中,当用户更改偏好设置时,UserSettings 的 @Published 属性将被更新,SettingsView 将自动刷新。
另一方面,@StateObject 将符合 ObservableObject 协议的对象标记为当前视图拥有的状态对象。这意味着当被 @StateObject 标记的对象发生变化时,它只会影响拥有该对象的视图。通常,@StateObject 用于在单个视图中管理状态。
例如,假设有一个符合 ObservableObject 的 TimerModel 类,用于管理计时器的状态。
class TimerModel: ObservableObject {
@Published var time: Double = 0
init() {
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
self.time += 1
}
}
}
我们可以使用 @StateObject 创建一个拥有 TimerModel 的状态变量,如下所示。
struct TimerView: View {
@StateObject var timerModel = TimerModel()
var body: some View {
Text("\(timerModel.time)")
}
}
在这个例子中,当 TimerModel 对象的 @Published 属性发生变化时,只有 TimerView 会受到影响。其他视图不会收到任何更新。
真正的区别#
在前面的例子中没有明确的区别。那么为什么用 @StateObject 包装的对象只会影响当前视图呢?
在上面的例子中确实没有太多区别。但是当 @ObservableObject 的对象被其父视图传递到两个视图时,就会有显著的区别。
当我们在视图中使用 @StateObject 创建对象实例时,该实例将与视图具有相同的生命周期,这意味着它将在视图被销毁时被销毁。
因此,使用 @StateObject 包装的对象只会存在于当前视图中,并且只会影响当前视图。如果其他视图需要相同的对象,则应使用 @ObservedObject 包装器。
在上面的例子中,我们使用 @StateObject 包装器创建了一个 TimerModel 实例,并将其存储在 timerModel 的属性中。因此,timerModel 对象只存在于 TimerView 中,其他视图无法访问。
下面是一个 ObservableObject 的对象被多个视图观察的例子。
class UserSettings: ObservableObject {
@Published var theme: Theme = .light
}
struct SettingsView: View {
@ObservedObject var userSettings: UserSettings
var body: some View {
VStack {
Text("设置视图")
Text("当前主题: \(userSettings.theme.rawValue)")
}
}
}
struct ProfileView: View {
@ObservedObject var userSettings: UserSettings
var body: some View {
VStack {
Text("个人资料视图")
Text("当前主题: \(userSettings.theme.rawValue)")
}
}
}
struct ContentView: View {
@StateObject var userSettings = UserSettings()
var body: some View {
VStack {
SettingsView(userSettings: userSettings)
ProfileView(userSettings: userSettings)
}
}
}
在这个例子中,当用户更新 userSettings 的主题属性时,SettingsView 和 ProfileView 将自动更新并显示最新的主题。这是多个视图观察同一个 ObservableObject 协议对象的基本实现。
如果我们在 SettingsView 或 ProfileView 中使用 @StateObject,就像我们将参数传递给两个视图,并且它们各自在自己的上下文中创建了一个副本。在这种情况下,状态变化将被限制在各自的上下文中,并且不会相互影响。
分享一张作为帖子封面的图片
这是我昨天为 Jaina 生成的头像。她非常喜欢。