我创建了一个像这样的模型:
class TestModel: ObservableObject {
@Published var num: Int = 0
}
模型用于“主页”视图和“主页”的子视图“ HomeSub”
struct Home: View {
@StateObject var model = TestModel()
var body: some View {
NavigationView(content: {
NavigationLink(destination: HomeSub(model: model)) { Text("\(model.num)") }
})
}
}
struct HomeSub: View {
//1
@StateObject var model = TestModel()
//2
@ObservedObject var model = TestModel()
var body: some View {
VStack {
Text("\(model.num)")
.padding()
.background(Color.red)
Button("Add") {
model.num += 1
}
}
.onChange(of: model.num, perform: { value in
print("homeSub: \(value)")
})
}
}
在HomeSub视图中,1和2有什么区别? 当我运行项目时,它们具有完全相同的行为。
答案 0 :(得分:1)
在撰写本文时,@StateObject
和@ObservedObject
在子视图中都做相同的事情。但是,这都不对,因为他们不必要地创建新的TestModel
只是为了扔掉它并用传入的值替换它。
编写子视图的正确方法是:
@ObservedObject var model: TestModel
在这种情况下,子视图中没有为model
分配初始值,这意味着调用者将必须提供它。这正是您想要的。一个真理来源,即父视图中的model
。
此外,视图的状态变量(@State
和@StateObject
)应为private
,并始终标记为private
。如果您这样做:
@StateObject private var model = TestModel()
在子视图中,您将无法从父视图传递模型,并且您会看到在这种情况下只能使用@ObservedObject
。
在进一步测试中,当Swift / SwiftUI编写为TestModel
时似乎避免在子视图中创建@ObservedObject var model = TestModel()
,但是语法仍然会误导读者,应该仍然是之所以写成@ObservedObject var model: TestModel
,是因为它清楚表明model
是从其他地方(即从父视图)初始化的。
答案 1 :(得分:0)
它们几乎可以互换使用,并且在您的设置中创建同一模型的2个实例。
@StateObject
的生命周期由SwiftUI管理,仅在iOS 14+中可用。
https://developer.apple.com/documentation/swiftui/stateobject
@ObservableObject
的生命周期由开发人员管理(有时可以通过刷新View
来无意重新初始化,因为它应该来自父View
),它可以在iOS 13以上版本。
https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
答案 2 :(得分:0)
在这种情况下,最好在从父级注入值时使用@ObservedObject
。 @StateObject
旨在在View上独立保存一个对象(其生命周期由SwiftUI管理)。由于注射,这里不需要。