我一直在学习swiftUI和@StateObject
和@ObservedObject
,并认为我掌握了它,直到我意识到我可以将@ObservedObject
与@StateObject
交换,而不会对代码行为产生任何影响。考虑这个例子:
class SharedModel: ObservableObject {
@Published var value: String = "Initial Value"
}
struct ContentView: View {
@StateObject var sharedModel = SharedModel()
var body: some View {
VStack {
Text("Value in ContentView: \(sharedModel.value)")
TextField("ContentView textfield", text: $sharedModel.value)
SubView(sharedModel: sharedModel)
}
}
}
struct SubView: View {
@ObservedObject var sharedModel: SharedModel
var body: some View {
VStack {
Text("Value in SubView: \(sharedModel.value)")
TextField("sub textfield", text: $sharedModel.value)
}
}
}
字符串
在TextField
中写入内容将更新两个Text
视图中的文本。因此,当SharedModel的属性更新时,ContentView和SubView将更新。很好。但后来我玩了一下,将@ObservedObject
更改为@StateObject
,并没有注意到任何差异。它和以前一样工作。我认为它的工作方式是,如果属性用@StateObject
则它是真实的来源,不会将更改中继到其他@StateObject
属性。
那么这里的问题是什么呢?@ObservedObject
的意义是什么?如果@StateObject
同样可以正常工作,我为什么要使用它?
4条答案
按热度按时间cedebl8k1#
StateObject
的主要区别是它在SwiftUI中有存储空间,当View
重新加载时,它可以保留一个对象。您可能没有注意到任何差异,但使用
ObservedObject
进行初始化将导致泄漏,不一致的行为和不必要的数据丢失。SwiftUI可能随时创建或重新创建视图,因此使用给定的输入集初始化视图总是会导致相同的视图,这一点很重要。因此,在视图中创建观察对象是不安全的。相反,SwiftUI提供了StateObject属性 Package 器,该 Package 器为您存储在视图层次结构中的引用类型创建单个真实值源。
https://developer.apple.com/documentation/swiftui/monitoring-model-data-changes-in-your-app
当从
StateObject
到StateObject
时,你不会得到一个新的对象,因为它是一个class
是一个引用类型,它们都指向同一个地址。你需要一个“深”副本,让它们完全不同。你会有两个不同的o next试图在SwiftUI中拥有相同的东西,所以你可能最终会泄漏。
新的
Observable
可以做你所描述的,如果你传递一个Observable
到一个State
SwiftUI现在为你创建一个深副本。qlfbtfca2#
你说的是三件不同的事情:
@ObservedObject
是一个属性 Package 器,用于-类似于值类型@Binding
-不属于当前视图的引用类型对象。在SwiftUI的第一个版本中,它也是当前视图拥有的对象的属性 Package 器。@StateObject
是一个属性 Package 器,与值类型@State
类似,专门用于当前视图所拥有的引用类型对象。在SwiftUI的后续版本中,它已经取代了@ObservedObject
用于 owned 类型。出于兼容性原因,@ObservedObject
仍然可以工作,但不推荐使用。ObservableObject
是一个协议,并且是使用@StateObject
Package 器创建的类所必需的。每当其@Published
属性发生更改时,它就会刷新受影响的视图。请注意
ObservableObject
和@ObservedObject
之间的区别。irlmq6kh3#
在SwiftUI的第一个版本中,我们只有
@ObservedObject
,其中对象由其他对象拥有,例如由单例拥有,在@Published
数组中存储所有模型结构并负责加载和保存。然后在第二个版本中添加了@StateObject
,它提供了View
拥有对象的能力,并在屏幕出现时初始化,当它消失时de-init,即将其用于通过合并管道加载的MVC视图数据。由于现在我们可以使用支持MVC/await的.task
来管理与视图数据相关的MVC工作的生命周期,因此我们不再需要@StateObject
。对于非JavaScript视图数据,我们使用
@State
(可以将相关的变量分组在结构中),let
和@Binding var
,并避免使用像您的示例代码中那样会减慢SwiftUI的重量级对象。xyhw6mcr4#
@ObservableObject:
字符串
}
struct ContentView:View { @ObservedObject var userData:UserData = UserData()
型
}
@StateObject:
型
}
struct ContentView:View { @StateObject var userData:UserData = UserData()
型
总之,@ObservableObject用于将外部可观察对象注入到视图中,而@StateObject用于管理在视图中创建的可观察对象的生命周期。根据对象是由视图本身创建和拥有还是由多个视图共享来选择适当的属性 Package 器是至关重要的。