Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between @EnvironmentObject and @ObservedObject?

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.

like image 400
Dakata Avatar asked Aug 10 '20 16:08

Dakata


People also ask

What is the difference between StateObject and ObservedObject?

ObservedObjects are usually used when the data is stored outside of the view so when the view is redrawn, we won't lose the data. StateObjects are usually used when that data needs to be stored inside of the view. Many people are confused by these two property wrappers.

What is @ObservedObject?

When using observed objects there are three key things we need to work with: the ObservableObject protocol is used with some sort of class that can store data, the @ObservedObject property wrapper is used inside a view to store an observable object instance, and the @Published property wrapper is added to any ...

What is StateObject?

A property wrapper type that instantiates an observable object.

How does @StateObject work?

If you're finding it hard to remember the distinction, try this: whenever you see “State” in a property wrapper, e.g. @State , @StateObject , @GestureState , it means “the current view owns this data.” SPONSORED In-app subscriptions are a pain. The code can be hard to write, hard to test, and full of edge cases.

What is the difference between @observedobject and @environmentobject property wrapper?

So if you want the ObservableObject you create to be reset or recreated every time the view is discarded and reappeared, you should mark the property with @ObservedObject. I’d like to think @EnvironmentObject property wrapper is a more global version of @State, or to be more precise, an @ObservedObject.

What is the difference between @stateobject and @observedobject?

You should use @StateObject for any observable properties that you initialize in the view that uses it. But if the ObservableObject is created externally and passed to the view or even shared among views, you should use @ObservedObject. Since @StateObject couldn’t accomplish that.

How to use @environmentobject in a view?

The way @EnvironmentObject works is when called within a view, it looks from an object of that type in the environment (in other words, from any parent above it that has specified an environmentObject ), and then lets you use it.

What happens when an observable object has several views?

If the observable object happens to have several views using its data, either option will automatically notify them all. Warning: When you use a custom publisher to announce that your object has changed, this must happen on the main thread. What is @StateObject? Somewhere between @State and @ObservedObject lies @StateObject.


1 Answers

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.

like image 179
pawello2222 Avatar answered Oct 20 '22 09:10

pawello2222