SwiftUI: @Environment vs @EnvironmentObject

One of the awesome things about SwiftUI is its property wrappers. I came across @Environment and @EnvironmentObject several times while learning SwiftUI and at first the differences were not clear to me so I thought I’d explain them with this blog post.

Both @Environmentand @EnvironmentObject property wrappers read values from the environment. Unlike @EnvironmentObject the @Environment property wrapper reads values using a specified key path. In the example below, we use @Environment to read an environment value from the key path .\editMode.

import SwiftUI

struct ProfileHost: View {
    @Environment(\.editMode) var mode
    var body: some View {
        VStack {
            if self.mode?.wrappedValue == .inactive {
                Text("Not in edit mode")
            } else {
                Text("In edit mode")
            }
        }
    }
}

The @EnvironmentObject enables the sharing of data between views through the injection of values into the environment. It also invalidates the current view whenever it’s value changes causing the view to refresh. Suppose we have an observable object AccountSettings

import SwiftUI
import Combine

final class AccountSettings: ObservableObject {
    @Published var enableNotifications = false
    @Published var enableReminders = true
}

When the value of AccountSettings is placed in the environment it can be retrieved by any view within that environment and whenever it’s value changes the view is invalidated and refreshed. We can place the AccountSettings in the HomeView using e.g HomeView().environmentObject(AccountSettings())). The observable object value can then be retrieved by views within the environment as shown below.

import Combine
import SwiftUI

struct Settings: View {
   @EnvironmentObject var accountSettings:AccountSettings
   var body: some View {
     // The rest of the view code placed here
   }
}

Conclusion

SwiftUI property wrappers are great and worth understanding well to make the most of SwiftUI. @Environment retrieves values from the environment using a key path while @Environment is great for passing data between views to be retrieved directly from the environment.

References