swiftUI 子视图中的@StateObject 和@ObservedObject 有什么区别
What is the difference between @StateObject and @ObservedObject in child views in swiftUI
我创建了一个这样的模型:
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有什么区别?
当我 运行 项目时,它们具有完全相同的行为。
如您所写,@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()
,但该语法仍然误导 reader 并且它仍然应该写成 @ObservedObject var model: TestModel
因为这清楚地表明 model
是从其他地方(即从父视图)初始化的。
它们几乎可以互换使用,并且在您的设置中创建同一模型的 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
在这种情况下,最好使用 @ObservedObject
,因为您要从父级注入值。 @StateObject
旨在在 View 上独立保存一个对象(它的生命周期由 SwiftUI 管理)。这里因为注入不需要了
我创建了一个这样的模型:
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有什么区别? 当我 运行 项目时,它们具有完全相同的行为。
如您所写,@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()
,但该语法仍然误导 reader 并且它仍然应该写成 @ObservedObject var model: TestModel
因为这清楚地表明 model
是从其他地方(即从父视图)初始化的。
它们几乎可以互换使用,并且在您的设置中创建同一模型的 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
在这种情况下,最好使用 @ObservedObject
,因为您要从父级注入值。 @StateObject
旨在在 View 上独立保存一个对象(它的生命周期由 SwiftUI 管理)。这里因为注入不需要了