问题
I have been reading about the property wrappers in SwiftUI and I see that they do a great job, but one thing which I really don't get is the difference between @EnvironmentObject and @ObservedObject.
From what I learned so far, I see that @EnvironmentObject is used when we have an object that is needed in various places in our app but we don't need to pass it through all of them. For example if we have hierarchy A -> B -> C -> D and the object is created at A, it is saved in the environment so that we can pass it directly from A to D, if D needs it.
If we use @ObservedObject which is created at A and needs to be passed to D, then we need to go through B and C as well.
But I still don't know how to decide which one to use. Here are 2 example projects which I made:
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"
}
and
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"
}
Both codes do the same update of the view. Also both ContentViews, pass an Order object. The difference is that Environment passes .environmentObject(order) and Observed passes it directly EditView(order: order). For me, both do same job, only their declaration is different, therefore I would appreciate some explanation or a better example.
回答1:
As you've noticed an @ObservedObject
needs to be passed from view to view. It may be better for a simple view hierarchy when you don't have too many views.
Let's assume you have the following hierarchy:
ViewA -> ViewB -> ViewC -> ViewD
Now if you want your @ObservedObject
from the ViewA
to be in the ViewB
there's no problem with passing it directly in init
.
But what if you want it in the ViewD
as well? And what if you don't need it in the ViewB
and ViewC
?
With an @ObservedObject
you'd need to manually pass it from the ViewA
to the ViewB
and then to the ViewC
, and then to the ViewD
. And you'd need to declare it in every child view.
With an @EnvironmentObject
it's easy - just pass it to the top-level view:
ViewA().environmentObject(someObservableObject)
Then you only declare it in the view that uses it - this may make your code more readable.
Note
Every object in the environment (view hierarchy) can access the injected @EnvironmentObject
. If you don't want this (privacy is important) you may need to pass it as an @ObservedObject
instead.
来源:https://stackoverflow.com/questions/63343819/what-is-the-difference-between-environmentobject-and-observedobject