我正在 SwiftUI 中开发一个 iOS 应用程序,其中我有一个共享的 ObservableObject,我想在多个视图之间传递它。该对象旨在跟踪某些共享应用程序状态,例如用户设置或会话数据。
在我的一种观点中,我使用@StateObject来创建该对象的实例。但是,我注意到我对另一个视图中的 ObservableObject 所做的任何更改都会导致我的原始视图意外更新。就好像该对象在多个地方被观察一样,尽管我认为 @StateObject 会使其在声明它的视图中保持隔离。
这是我的代码的简化版本:
import SwiftUI
class SharedData: ObservableObject {
@Published var counter: Int = 0
}
struct ParentView: View {
var body: some View {
VStack {
CounterView()
AnotherView()
}
}
}
struct CounterView: View {
@StateObject private var data = SharedData()
var body: some View {
VStack {
Text("Counter: \(data.counter)")
Button("Increment Counter") {
data.counter += 1
}
}
}
}
struct AnotherView: View {
@ObservedObject var data = SharedData() // <- Issue?
var body: some View {
Text("Another View Counter: \(data.counter)")
}
}
当我增加 CounterView 中的计数器时,AnotherView 也会反映 data.counter 中的变化。我不明白为什么 AnotherView 会在 CounterView 递增 data.counter 时更新,因为我认为每个视图都会管理自己的实例。
随
ObservedObject
属性包装器提供的属性不应具有默认值或初始值。
Apple对此也说得很清楚在文档中:
因此,不要为观察对象指定默认值或初始值。仅将该属性用于充当视图输入的属性,如上面的示例所示。
ObservedObject
包装的属性应始终作为依赖项注入到视图中,而永远不要在视图本身中创建。
这样做的背景是,否则,每次重新创建视图时,都会生成一个新的实例
ObservableObject
创建了符合要求的模型实例。如果您想在视图/视图实例之间共享状态,这正是您不想要的。
因此您可以在代码中执行以下操作:
struct ParentView: View {
@StateObject private var data = SharedData()
var body: some View {
VStack {
CounterView(data: data)
AnotherView(data: data)
}
}
}
struct CounterView: View {
@ObservedObject var data: SharedData
var body: some View {
VStack {
Text("Counter: \(data.counter)")
Button("Increment Counter") {
data.counter += 1
}
}
}
}
struct AnotherView: View {
@ObservedObject var data: SharedData
var body: some View {
Text("Another View Counter: \(data.counter)")
}
}