12

What is the purpose of @EnvironmentObject when we have @Binding property wrapper ? I am having trouble figuring out why @EnvironmentObject is needed. I took a look at these posting but its not quite what I am looking for EnvironmentObject in SwiftUI How to use BindableObjects (EnviromentObject)?

I also looked at their documentation which was too thin. https://developer.apple.com/documentation/swiftui/environmentobject

mfaani
  • 33,269
  • 19
  • 164
  • 293
Chéyo
  • 9,107
  • 9
  • 27
  • 44
  • 1
    [Data Flow Through SwiftUI talk from WWDC 2019](https://developer.apple.com/videos/play/wwdc2019/226/) covers precisely this. `EnvironmentObject` is mentioned at 26:45, though I recommend watching entire talk. – Alexander Sep 10 '19 at 15:34

1 Answers1

47

I'll try to explain generally. We have the next modifiers @State, @StateObject, @ObservedObject @Published, @EnvironmentObject, and @Binding.

  1. @State - declares local value property. Apple recommends using them as less as possible because the @State property should be used only inside the view and be responsible for small UI things. It should have a simple value type, not a reference type, otherwise, it won't update the UI for you.
  2. @StateObject - declares and instantiates object instance. Usually, it is your data model that should be displayed. The object must conform to the ObservableObject protocol.
  3. @ObservedObject - declares a property that uses an instance marked as a @StateObject that has been passed from the parent view. It is a good choice when you do not want your reusable view to be dependent on the external objects. This way you passing the @StateObject directly to each child view.
  4. @EnvironmentObject - also declares a property as a @ObservedObject does, but this modifier should be used when you pass an instance to all subviews tree. To pass the instance to the child view just call YourViewToPresent().environmentObject(<your object>). And then this child view and its children can access an instance using @EnvironmentObject var instance: YourInstance without additional effort or passings. This modifier finds an instance of the declared type, so you cannot declare more than one object of the same type in the same environment. You also should be careful and do not use it too much since this may open a lot of architectural backdoors on your project(library, framework).
  5. @Published - should be used to mark ObservableObject variable to re-render the view when it's changed.
  6. @Binding - defines that the property can modify real Source of Truth(@State, @ObservedObject, @EnvironmentObject). When you are passing one of the properties from 1-3 points to the view you have to declare the property in child view as @Binding to create a reference. Use $ sign to pass the Source of Truth to the child: MessageDetails(message: $message). By changing the @Binding you will be changing actual Source of Truth. For more info recommend to watch Data Flow Through SwiftUI

Bonus: @Environment - is used to get environment values by using keyPath @Environment(\.colorScheme). You can read this value, but you cannot set this value. If the value is changed it causes UI re-render. Some values may be updated updated by SwiftUI. To find all available keys look for documentation of the EnvironmentValues. You also can override as well as add custom EnvironmentValue.

DenFav
  • 2,683
  • 1
  • 18
  • 27
  • Additionally: `state` is usually private. Like an internal view state e.g. `shouldShowView`. For `ObservedObject` , think of state, but something that its value comes from outside your object and perhaps one that the view can also update the value of the model ie it's two way. For `EnvironmentObject` see it as _shared_ variables, it's very close to Singletons. Ultimately think of `Binding` as something that is a pass through. Not sure if this is a good example, but weak references are never that which retains the memory, similarly `Binding` is not what causes changes, it only passes them on – mfaani Nov 28 '20 at 15:23
  • Thanks for the additions. I just would like to clarify: 'EnvironmentObject' is Dependency injections, rather than Singletons. Cause singletons are often used as antipatterns and I want to prevent beginners to use them a lot. Long story short: Dependency injection is a kind of array that contains a list of the instances(Observable objects), and the Xcode takes them for you when detects modifiers '@ObservedObject', '@EnvironmentObject' – DenFav Jul 18 '22 at 13:16