@ObservedObject 模型生命周期?
@ObservedObject model lifecycle?
我正在测试 @ObservedObject 以测试 SwiftUI 如何处理模型的生命周期。
根据我现在的理解,从 WWDC 视频和文档中,创建模型对象的视图(class 采用 ObservableObject
)应该使用 @StateObject
。
从 WWDC 视频中,他们清楚地指出 @ObservedObject
不 拥有观察到的实例生命周期。
所以我创建了这个简单的设置:
struct TestParentView: View {
@ObservedObject var model:TestModel
var body: some View {
VStack {
Text("TEST TEXT. \(model.name)")
TestChildView(model: model)
}
}
}
struct TestParentView_Previews: PreviewProvider {
static var previews: some View {
TestParentView(model: TestModel())
}
}
struct TestChildView: View {
@ObservedObject var model:TestModel
var body: some View {
Button(action: {
print("change name")
model.changeName()
}, label: {
Text("Change Name")
})
}
}
struct TestChildView_Previews: PreviewProvider {
static var previews: some View {
TestChildView(model: TestModel())
}
}
我这里使用的模型是这样的:
class TestModel:ObservableObject {
@Published var name:String = ""
let id = UUID()
func changeName() {
name = "\(UUID())"
}
deinit {
print("TestModel DEINIT. \(id)")
}
}
当我 运行 这个应用程序时,我期望在 TestParentView
中创建的 TestModel 实例至少在某个时候被取消初始化,因为 @ObservedObject
不拥有model
.
当我点击按钮触发名称更改时,一切正常,但从未调用 TestModel DEINIT。
从所有这些来看,TestParentView
似乎有一个 strong 对 TestModel 的引用,并且它永远不会放弃它。
那么,在这种情况下,当他们说 @ObservedObject
不管理 model
的生命周期时,他们是什么意思?
如果 @ObservedObject
不管理模型的生命周期,为什么从未调用 TestModel DEINIT?
我显然在这里遗漏了一些东西。
假定此视图:
struct Foo: View {
@ObservedObject var model = TestModel()
var body: some View {
Text(model.name)
}
}
每次创建此视图时,都会实例化 TestModel
的新实例。
SwiftUI 视图实际上更像是视图描述,它们在您的应用程序生命周期中被大量创建和销毁。因此,重要的是结构是轻量级的。 Foo 视图不是很轻量级,因为每次渲染过程都会实例化一个新模型。
如果您改为使用 @StateObject
,则框架只会在第一次实例化 TestModel
。之后它将重用同一个实例。这使它的性能更高。
经验法则:
- 如果视图创建自己的模型(例如 Foo 视图),请使用
@StateObject
。
- 如果模型是从外部传入的,则使用
@ObservedObject
。
回答您的问题:“为什么从未调用 TestModel DEINIT”。
您声明:“当我 运行 这个应用程序时,我期望在 TestParentView 中创建的 TestModel 实例至少在某个时候取消初始化”。
微妙的细节是 TestModel 不是 在 TestParentView
中创建的,它只是传入的。
它是在 TestParentView_Previews
中创建的。由于 TestParentView_Previews
的主体仅执行一次,因此 TestModel 也将仅初始化一次,因此永远不会被释放。
我正在测试 @ObservedObject 以测试 SwiftUI 如何处理模型的生命周期。
根据我现在的理解,从 WWDC 视频和文档中,创建模型对象的视图(class 采用 ObservableObject
)应该使用 @StateObject
。
从 WWDC 视频中,他们清楚地指出 @ObservedObject
不 拥有观察到的实例生命周期。
所以我创建了这个简单的设置:
struct TestParentView: View {
@ObservedObject var model:TestModel
var body: some View {
VStack {
Text("TEST TEXT. \(model.name)")
TestChildView(model: model)
}
}
}
struct TestParentView_Previews: PreviewProvider {
static var previews: some View {
TestParentView(model: TestModel())
}
}
struct TestChildView: View {
@ObservedObject var model:TestModel
var body: some View {
Button(action: {
print("change name")
model.changeName()
}, label: {
Text("Change Name")
})
}
}
struct TestChildView_Previews: PreviewProvider {
static var previews: some View {
TestChildView(model: TestModel())
}
}
我这里使用的模型是这样的:
class TestModel:ObservableObject {
@Published var name:String = ""
let id = UUID()
func changeName() {
name = "\(UUID())"
}
deinit {
print("TestModel DEINIT. \(id)")
}
}
当我 运行 这个应用程序时,我期望在 TestParentView
中创建的 TestModel 实例至少在某个时候被取消初始化,因为 @ObservedObject
不拥有model
.
当我点击按钮触发名称更改时,一切正常,但从未调用 TestModel DEINIT。
从所有这些来看,TestParentView
似乎有一个 strong 对 TestModel 的引用,并且它永远不会放弃它。
那么,在这种情况下,当他们说 @ObservedObject
不管理 model
的生命周期时,他们是什么意思?
如果 @ObservedObject
不管理模型的生命周期,为什么从未调用 TestModel DEINIT?
我显然在这里遗漏了一些东西。
假定此视图:
struct Foo: View {
@ObservedObject var model = TestModel()
var body: some View {
Text(model.name)
}
}
每次创建此视图时,都会实例化 TestModel
的新实例。
SwiftUI 视图实际上更像是视图描述,它们在您的应用程序生命周期中被大量创建和销毁。因此,重要的是结构是轻量级的。 Foo 视图不是很轻量级,因为每次渲染过程都会实例化一个新模型。
如果您改为使用 @StateObject
,则框架只会在第一次实例化 TestModel
。之后它将重用同一个实例。这使它的性能更高。
经验法则:
- 如果视图创建自己的模型(例如 Foo 视图),请使用
@StateObject
。 - 如果模型是从外部传入的,则使用
@ObservedObject
。
回答您的问题:“为什么从未调用 TestModel DEINIT”。
您声明:“当我 运行 这个应用程序时,我期望在 TestParentView 中创建的 TestModel 实例至少在某个时候取消初始化”。
微妙的细节是 TestModel 不是 在 TestParentView
中创建的,它只是传入的。
它是在 TestParentView_Previews
中创建的。由于 TestParentView_Previews
的主体仅执行一次,因此 TestModel 也将仅初始化一次,因此永远不会被释放。