Ios SwiftUI中的ObservedObject和StateObject之间有什么区别

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

如果我在SwiftUI中有一个
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。