@EnvironmentObject和@ObservedObject有什么区别?

时间:2020-08-10 16:05:11

标签: swiftui observedobject property-wrapper environmentobject

我一直在阅读有关SwiftUI中的属性包装器的信息,我发现它们做得很好,但是我真正不了解的一件事是 @EnvironmentObject @ObservedObject

到目前为止,我了解到,当我们在应用程序的各个位置都需要一个对象时,便会使用 @EnvironmentObject ,但我们不需要将其传递给所有对象他们。例如,如果我们具有层次结构A-> B-> C-> D,并且该对象是在A处创建的,则将其保存在环境中,以便在D需要时将其直接从A传递到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"
   }

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 对象。区别在于环境通过 .environmentObject(order),而观察到的则直接通过 EditView(order:order)传递。对我来说,两者都做同样的工作,只是他们的声明是不同的,因此,请您提供一些解释或更好的示例。

1 个答案:

答案 0 :(得分:2)

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


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

ViewA -> ViewB -> ViewC -> ViewD

现在,如果您希望将@ObservedObject中的ViewA放入ViewB中,则直接将其传递到init中就没问题了。

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

使用@ObservedObject时,您需要将其从ViewA手动传递到ViewB,然后传递到ViewC,再传递到{{1} }。并且您需要在每个子视图中声明它。

使用ViewD很简单-只需将其传递到顶级视图即可:

@EnvironmentObject

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


注意

环境(视图层次结构)中的

每个对象都可以访问注入的ViewA().environmentObject(someObservableObject) 。如果您不希望这样做(隐私很重要),则可能需要将其作为@EnvironmentObject传递。