Skip to content
DeveloperMemos

Using @EnvironmentObject to share data in SwiftUI

SwiftUI, EnvironmentObject, Data sharing2 min read

SwiftUI provides several ways to share data between views, and one of the most powerful mechanisms is through the use of the @EnvironmentObject property wrapper. With this tool, you can create a single source of truth for your data, which can be accessed and modified by any SwiftUI view that needs it. In this post, we will explore how to use @EnvironmentObject to share data between SwiftUI views in a clean and efficient manner.

Defining an EnvironmentObject

First, let's define a class that will hold the data we want to share. This class needs to conform to the ObservableObject protocol, and its properties need to have the @Published property wrapper in order to trigger updates to any views that use them. Here's an example:

1class UserData: ObservableObject {
2 @Published var name = "John Doe"
3 @Published var age = 30
4}

In this case, we have defined a simple UserData class with two properties: name and age. Both are marked with @Published, which means that any changes made to them will trigger updates to any views that use them.

Next, we need to create an instance of UserData and make it available to our views(or inject it I guess?) through the use of the @EnvironmentObject property wrapper. We can do this in the SceneDelegate or AppDelegate depending on our app's architecture:

1let userData = UserData()
2
3~~~
4
5ContentView()
6 .environmentObject(userData)

Here we have created an instance of UserData and passed it to the ContentView using the environmentObject(_:) modifier. From this point on, any view that needs to access UserData can simply declare it as an @EnvironmentObject property.

Accessing an EnvironmentObject

To access an @EnvironmentObject property, you simply declare it as a property in your view. For example, if we wanted to display the user's name and age in a Text view, we could do something like this:

1struct ProfileView: View {
2 @EnvironmentObject var userData: UserData
3
4 var body: some View {
5 VStack {
6 Text("Name: \(userData.name)")
7 Text("Age: \(userData.age)")
8 }
9 }
10}

In this case, we have declared userData as an @EnvironmentObject property and used it to display the user's name and age in two separate Text views. Because userData is marked with @Published, any changes made to it will automatically trigger updates to this view.

Modifying an EnvironmentObject

Finally, let's take a look at how we can modify an @EnvironmentObject property. To do this, we simply call a method on the object that changes its state. For example, if we wanted to change the user's name, we could do something like this:

1Button("Change Name") {
2 userData.name = "Jane Doe"
3}

This will update the name property of our UserData instance, which will trigger updates to any views that use it. This means that if we have a ProfileView open while we tap this button, the Text view displaying the user's name will automatically update to show the new value.

Conclusion

In this post, we've seen how to use @EnvironmentObject to share data between SwiftUI views. By defining an ObservableObject and making it available as an environment object, we can create a single source of truth for our data and make it easily accessible to any view that needs it. We can also modify this data in a clean and efficient manner, using the @Published property wrapper to trigger updates to our views.

SwiftUI provides many tools for data sharing, but @EnvironmentObject is one of the most powerful and flexible mechanisms available. By using it effectively, we can create clean, well-organized SwiftUI code that is easy to understand and maintain.