NEW: Get your ticket for Hacking with Swift Live 2019! >>

< How to respond to view lifecycle events: appear and disappear   How to use @ObjectBinding to create object bindings >

What’s the difference between @ObjectBinding, @State, and @EnvironmentObject?

State is inevitable in any modern app, but with SwiftUI it’s important to remember that all of our views are simply functions of their state – we don’t change the views directly, but instead manipulate the state and let that dictate the result.

SwiftUI gives us several ways of storing state in our application, but they are subtly different and it’s important to understand how they are different in order to use the framework properly.

In all the state examples we’ve so far we’ve use @State to create properties like this:

struct ContentView : View {
    @State var score = 0
    // more code

This creates a property inside a view, but it uses the @State property wrapper to ask SwiftUI to manage the memory. This matters: all our views are structs, which means they can’t be changed, and if we couldn’t add 1 to a score in a game then it isn’t much of a game.

So, when we say @State to make a property, we hand control over it to SwiftUI so that it remains persistent in memory for as long as the view exists. When that state changes, SwiftUI knows to automatically reload the view with the latest changes so it can reflect its new information.

@State is great for simple properties that belong to a specific view and never get used outside that view, so as a result it’s usually a good idea to mark those properties as being private, like this:

@State private var score = 0

This re-enforces the idea that such state is specifically designed never to escape its view.

What is @ObjectBinding?

For more complex properties – when you have a custom type you want to use that might have multiple properties and methods, or might be shared across multiple views – you should use @ObjectBinding instead.

This is very similar to @State except now we’re using an external reference type rather than a simple local property like a string or an integer. You’re still saying that your view depends on data that will change, except now it’s data you’re responsible for managing yourself – you need to create an instance of the class, create its own properties, and so on.

Whatever type you use with @ObjectBinding should conform to the BindableObject protocol, which has only one requirement: your type must implement some sort of didChange property that notifies the view when its data has changed.

This is what I mean when I say it’s data you’re responsible for managing yourself – when you set a property on your bound object you get to decide whether that should force the view to refresh or not. You usually will, but it’s not required.

An bindable object can notify its view that important data has changed using publishers from the Combine framework. If the bindable object happens to have several views using its data, then it will automatically notify them all.

Warning: When you use a publisher to announce that your object has changed, this must happen on the main thread.

What is @EnvironmentObject?

You’ve seen how @State declares simple properties for a type that automatically cause a refresh of the view when it changes, and how @ObjectBinding declares a property for an external type that may or may not cause a refresh of the view when it changes. Both of these two must be set by your view, but @ObjectBinding might be shared with other views.

There’s a third type of property available to use, which is @EnvironmentObject. This is a value that is made available to your views through the application itself – it’s shared data that every view can read if they want to. So, if your app had some important model data that all views needed to read, you could either hand it from view to view to view or just put it into the environment where every view has instant access to it.

Think of @EnvironmentObject as a massive convenience for times when you need to pass lots of data around your app. Because all views point to the same model, if one view changes the model all views immediately update – there’s no risk of getting different parts of your app out of sync.

Summing up the differences

  • Use @State for simple properties that belong to a single view. They should usually be marked private.
  • Use @ObjectBinding for complex properties that might belong to several views. Any time you’re using a reference type you should be using @ObjectBinding for it.
  • Use @EnvironmentObject for properties that were created elsewhere in the app, such as shared data.

Of the three you will find that @ObjectBinding is both the most useful and the most commonly used, so if you’re not sure which to use start there.

HACKING WITH SWIFT LIVE This July is a new two-day event where you'll be inspired by great speakers on day one then learn all the amazing new features from WWDC on day two – click here for more information and tickets.

< How to respond to view lifecycle events: appear and disappear   How to use @ObjectBinding to create object bindings >
Buy Testing Swift Buy Practical iOS 12 Buy Pro Swift Buy Swift Design Patterns Buy Swift Coding Challenges Buy Server-Side Swift (Vapor Edition) Buy Server-Side Swift (Kitura Edition) Buy Hacking with macOS Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with Swift Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let me know!

Click here to visit the Hacking with Swift store >>