SwiftUI Fundamentals

Feb 28 2023 · Swift 5.7, macOS Venture 13.1, Xcode 14.2

Part 2: Navigation & Data Flow

18. Environment

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 17. Challenge: StateObject & ObservableObject Next episode: 19. Conclusion

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 18. Environment

What if you have some data that lots of parts of your app depend on, like your user model?

Rather than passing that model through a bunch of initializers to all of your views, you can pass it via the Environment itself as an EnvironmentObject.

The Environment already contains lots of useful information that can be fed through all of the Views in your app, like color scheme, size class, and user font size.

To use an environment object you need three things.

One: A class conforming to ObservableObject. You’ve got that!

Two: Have at least one variable in the class with the @Published property wrapper to trigger any observers to update.

We’ve got that too!

Third, you need to pass an instance of the observable class to a view by using the environmentObject() view modifier when you create that view.

And the place to do that is in main app file. That’s the SwiftUI file where the @main entry point is declared.

  • Find the place where our main view, MovieList, is created.
  • And pass it a new UserStore as an environment object!
MovieList()
  .environmentObject(UserStore())

Now you can go back to MovieList.swift…

  • and change this ObservedObject to an Environment Object, and that’ll grab the instance you just made.
@EnvironmentObject var userStore: UserStore

You’ll be able to do the same in the UserView, so, get rid of this bit

leading:
  NavigationLink(destination: UserView(❌userStore: userStore❌))

and head over to UserView to fix that up now with another EnvironmentObject

@EnvironmentObject var userStore: UserStore

If you need a reference to an environment object for a preview to work, you can add it just like you did in the main app file.

struct UserView_Previews: PreviewProvider {
  static var previews: some View {
    UserView()
      .environmentObject(UserStore())
  }
}

Now, the last place I mentioned you might use the userstore is in AddMovie

@EnvironmentObject var userStore: UserStore

You can say, when this view appears, you want to set the genre to the favorite genre.

.onAppear { genre = userStore.currentUserInfo.favoriteGenre }

GenrePicker‘s selection then updates to the favorite genre, thanks to data flow.

You can test this out yourself with a live preview from MovieList

  • You’ll need to add the environmentObject to the preview first
static var previews: some View {
  MovieList(movieStore: MovieStore())
    .environmentObject(UserStore())
}
  • Set some user info
  • Click the update button. It won’t automatically dismiss, but you can fix that in a minute.
  • If you manually dismiss, watch the username update in MovieList!
  • and if you go to add a movie…
  • Your favorite genre should be automatically picked for you!

I did mention at the start of this episode that there’s another way to use the environment.

Go back to UserView.swift.

And add this line along with the rest of the property declarations:

@Environment(\.dismiss) var dismiss

This new property wrapper, @Environment, is like @EnvironmentObject in one way: both are shared across a view hierarchy.

The difference is that you can add anything as an environment object, but environment values are more like key-value pairs.

You usually use @EnvironmentObject to manage dependencies in your app. SwiftUI uses @Environment as a way to manage settings for views and their children.

Each view comes with environment values you can use to change the behavior of views in the hierarchy. One of these values is dismiss.

This keypath property can also be called like a function, so you can use it to dismiss the view from the updateUserInfo method.

dismiss()

When you call dismiss(), the view hierarchy will dismiss the current view, which, in this case, is UserView.

I have a second preview here that shows the movie list. Tap the user icon

Add some user data Save it… and there you go! The view dismisses and returns to the movie list screen.

Nice work.