Ios SwiftUI中的ObservedObject和StateObject之间有什么区别
如果我在SwiftUI中有一个Ios SwiftUI中的ObservedObject和StateObject之间有什么区别,ios,swift,swiftui,Ios,Swift,Swiftui,如果我在SwiftUI中有一个ObservedObject,我可以将其称为@ObservedObject: class ViewModel: ObservableObject { @Published var someText = "Hello World!" } struct ContentView: View { @ObservedObject var viewModel = ViewModel() var body: some Vie
ObservedObject
,我可以将其称为@ObservedObject
:
class ViewModel: ObservableObject {
@Published var someText = "Hello World!"
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
Text(viewModel.someText)
}
}
class ViewModel: ObservableObject {
@Published var someText = "Hello World!"
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
Text(viewModel.someText)
}
}
或者作为@StateObject
:
class ViewModel: ObservableObject {
@Published var someText = "Hello World!"
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
Text(viewModel.someText)
}
}
class ViewModel: ObservableObject {
@Published var someText = "Hello World!"
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
Text(viewModel.someText)
}
}
但两者之间的实际区别是什么?是否存在一种情况比另一种更好,或者是两种完全不同的情况?@ObservedObject 当视图创建自己的
@ObservedObject
实例时,每次丢弃并重新绘制视图时,都会重新创建该实例:
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
}
相反,@State
变量将在重画视图时保留其值
class ViewModel: ObservableObject {}
struct ParentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
ChildView(viewModel: viewModel) // You inject the view model into the child view
}
}
// Even if `ChildView` is discarded/redrawn, `ViewModel` is kept in memory, since `ParentView` still holds a reference to it - `ViewModel` is only released and hence destroyed when `ParentView` is destroyed/redrawn.
struct ChildView: View {
@ObservedObject var viewModel: ViewModel
}
@StateObject
@StateObject
是@ObservedObject
和@State
的组合-即使在放弃和重新绘制视图后,视图模型的实例仍将被保留和重用:
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
}
性能
虽然如果视图经常被迫重新创建重量级对象,则@ObservedObject
可能会影响性能,但当@ObservedObject
不复杂时,这应该没有多大关系
何时使用@ObservedObject
现在似乎没有理由使用@ObservedObject
,那么什么时候应该使用它呢
您应该将@StateObject用于您需要的任何可观察属性
在使用它的视图中初始化。如果observeObject实例
是在外部创建的,并传递给使用它的视图以标记您的
带有@ObservedObject的属性
注意,可能的用例太多,有时可能需要在视图中重新创建可观察的属性。在这种情况下,最好使用@ObservedObject
有用链接:
尽管我们已经很好地解释了视图本身创建其视图模型时的差异,但在将视图模型注入视图时注意差异是很重要的
将视图模型注入视图时,只要视图模型是引用类型,@ObservedObject
和@StateObject
之间没有区别,因为将视图模型注入视图的对象也应该包含对视图模型的引用,因此,重画子视图时不会破坏视图模型
class ViewModel: ObservableObject {}
struct ParentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
ChildView(viewModel: viewModel) // You inject the view model into the child view
}
}
// Even if `ChildView` is discarded/redrawn, `ViewModel` is kept in memory, since `ParentView` still holds a reference to it - `ViewModel` is only released and hence destroyed when `ParentView` is destroyed/redrawn.
struct ChildView: View {
@ObservedObject var viewModel: ViewModel
}
是否解释了为什么使用ObservedObject
初始化不安全
SwiftUI可能会在任何时候创建或重新创建视图,因此使用给定的输入集初始化视图始终会产生相同的视图,这一点很重要。因此,在视图中创建观察对象是不安全的
解决方案是StateObject
同时,文档向我们展示了如何在视图(或应用程序/场景)中创建数据模型,而视图(或应用程序/场景)可以保持真实性,并将其传递给另一个视图
结构库视图:视图{
@StateObject var book=book()//坚持1真理
var body:一些观点{
BookView(book:book)//将其传递给另一个视图
}
}
结构书视图:视图{
@ObservedObject变量book:book//来自外部源
}
以下是一个示例。每次单击refresh
按钮时,CountViewObserved
强制销毁/重新创建StateObjectClass,这样您就可以看到0
,这是不需要的
import SwiftUI
import Combine
class StateObjectClass:ObservableObject{
let type:String
let id:Int
@Published var count = 0
init(type:String){
self.type = type
self.id = Int.random(in: 0...1000)
print("type:\(type) id:\(id) init")
}
deinit {
print("type:\(type) id:\(id) deinit")
}
}
struct CountViewState:View{
@StateObject var state = StateObjectClass(type:"StateObject")
var body: some View{
VStack{
Text("@StateObject count :\(state.count)")
Button("+1"){
state.count += 1
}
}
}
}
struct CountViewObserved:View{
@ObservedObject var state = StateObjectClass(type:"Observed")
var body: some View{
VStack{
Text("@Observed count :\(state.count)")
Button("+1"){
state.count += 1
}
}
}
}
struct ContentView: View {
@State var count = 0
var body: some View {
VStack{
Text("refresh CounterView count :\(count)")
Button("refresh"){
count += 1
}
CountViewState()
.padding()
CountViewObserved()
.padding()
}
}
}
@StateObject
是给定视图的状态,因此它的实例由SwiftUI跨主体
更新保留。但在预览中运行时,它不会被保留
另一方面,@ObservedObject
只是给定的视图所观察到的对象,因此SwiftUI不会保留它(它必须保留在视图
之外)
换句话说,它看起来像SwiftUI保持了对@StateObject
的强引用和对@ObservedObject
的无主引用
,大约在8:30左右。我们可以说:
@观察对象变量手册:BookModel
及
@StateObject变量书:BookModel
@ObservedObject不拥有实例“book”,您有责任管理实例的生命周期
但是,当您想将ObserveObject“book”的生命周期与视图绑定在一起时,比如@State,您可以使用@StateObject。
在这种情况下,SwiftUI将拥有ObserveObject,并且创建和销毁将与视图的生命周期相关联
SwiftUI将使对象在视图的整个生命周期内保持活动状态
这对于昂贵的资源来说是非常好的,您不需要再摆弄onDisappear来释放资源
此澄清摘自SwiftUI中的WWDC2020数据要点:我不清楚是否存在任何用例观察对象,为什么它没有被弃用@DavidPasztor用例显示它们可以是等价的,但是什么时候ObservedObject会是第一选择?@RyanHeitner所有内容都在我提供的有用链接中。但是,因为不是每个人都会阅读它们,所以我在回答中添加了摘要。视图是否可能同时拥有这两种内容?@AbhijitSarkar是的,这些属性包装器应用于ObservableObject类,而不是视图本身。视图中可以同时具有StateObject和ObservedObject属性。由于引用类型正在传递到BookView,是否需要ObservedObject?我想知道你什么时候需要被观察到。哦,我想我知道了。没有ObservedObject,如果父对象(或其他源)对book StateObject进行更改,则不会将book发生的任何更改推送到BookView。