@EnvironmentObject 和@ObservedObject 有什么区别?

What is the difference between @EnvironmentObject and @ObservedObject?

我一直在阅读 SwiftUI 中的 属性 包装器,我发现它们做得很好,但我真正不明白的一件事是 @EnvironmentObject 之间的区别@ObservedObject.

根据我目前所学,我发现 @EnvironmentObject 当我们有一个对象在我们的应用程序的各个地方都需要但我们不需要时使用通过所有这些。例如,如果我们有层次结构 A -> B -> C -> D 并且对象是在 A 处创建的,它会保存在环境中,以便我们可以将它直接从 A 传递到 D,如果 D 需要的话。

如果我们使用在A处创建的@ObservedObject需要传递给D,那么我们还需要经过B和C。

但我仍然不知道如何决定使用哪一个。 这是我制作的 2 个示例项目:

struct ContentView2: View {
 
   var order = Order2()

   var body: some View {
      VStack {
           EditView2()
           DisplayView2()
       }
       .environmentObject(order)
   }
}
struct EditView2: View {
   @EnvironmentObject var user: Order2
 
   var body: some View {
       HStack{
       TextField("Fruit", text: $user.item)
       }
   }
}
struct DisplayView2: View {
   @EnvironmentObject var user: Order2
   var body: some View {
       VStack{
       Text(user.item)
       }
   }
}
class Order2: ObservableObject {
       @Published var item = "Orange"
   }

struct ContentView: View {

    var order = Order()
    
    var body: some View {
       VStack {
            EditView(order: order)
            DisplayView(order: order)
        }
    }
}
struct EditView: View {
    @ObservedObject var order: Order
    var body: some View {
        HStack{
        TextField("Fruit", text: $order.item)
        }
    }
}
struct DisplayView: View {
      @ObservedObject var order: Order
      var body: some View {
        VStack{
        Text(order.item)
        }
    }
}
class Order: ObservableObject {
    @Published var item = "Apple"
}

两个代码对视图进行相同的更新。此外,两个 ContentView 都传递一个 Order 对象。不同的是Environment传.environmentObject(order)而Observed直接传EditView(order: order)。对我来说,两者都做同样的工作,只是他们的声明不同,因此我希望得到一些解释或更好的例子。

如您所见,@ObservedObject 需要从一个视图传递到另一个视图。当您没有太多视图时,使用简单的视图层次结构可能会更好。


假设您具有以下层次结构:

ViewA -> ViewB -> ViewC -> ViewD

现在,如果您希望 ViewA 中的 @ObservedObject 出现在 ViewB 中,直接将其传递到 init 中没有问题。

但是如果您也想在 ViewD 中使用它怎么办?如果您在 ViewBViewC 中不需要它怎么办?

对于 @ObservedObject,您需要手动将其从 ViewA 传递到 ViewB,然后传递到 ViewC,然后再传递到 ViewD。而且您需要在每个子视图中声明它。

使用 @EnvironmentObject 很简单 - 只需将其传递给 top-level 视图即可:

ViewA().environmentObject(someObservableObject)

那么您只需在使用它的视图中声明它 - 这可能会使您的代码更具可读性。


备注

环境(视图层次结构)中的每个 对象都可以访问注入的@EnvironmentObject。如果您不想要这个(隐私很重要),您可能需要将其作为 @ObservedObject 传递。