@EnvironmentObject 和 @ObservedObject 有什么区别?

Dak*_*ata 6 swiftui property-wrapper observedobject environmentobject

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

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

如果我们使用在 A 创建并需要传递给 D 的@ObservedObject,那么我们也需要通过 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"
   }
Run Code Online (Sandbox Code Playgroud)

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"
}
Run Code Online (Sandbox Code Playgroud)

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

paw*_*222 6

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


假设您有以下层次结构:

ViewA -> ViewB -> ViewC -> ViewD
Run Code Online (Sandbox Code Playgroud)

现在,如果您希望您的@ObservedObjectfromViewA位于 the 中ViewB,则直接将其传入init.

但是如果你也想要它ViewD呢?如果在ViewBand 中不需要它怎么办ViewC

使用 ,@ObservedObject您需要手动将其从 传递ViewAViewB,然后传递到ViewC,然后传递到ViewD。而且您需要在每个子视图中声明它。

使用@EnvironmentObject它很容易 - 只需将其传递给顶级视图:

ViewA().environmentObject(someObservableObject)
Run Code Online (Sandbox Code Playgroud)

然后你只在使用它的视图中声明它 - 这可能会使你的代码更具可读性。


笔记

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

  • @Dakata不,不幸的是你需要将它再次注入到你的工作表中。但只有一次当你调用它时。然后工作表中的所有子视图都可以访问您的环境对象。可以把它想象成一张纸有它自己的环境。 (3认同)
  • 请注意,您可以使用私有类型作为 EnvironmentObject,这会阻止不知道该类型的范围访问它 (2认同)
  • 这是最好的解释,我完全理解了。谢谢你! (2认同)