SwiftUI – How to pass EnvironmentObject into View Model

Certainly! When working with SwiftUI, you can pass an EnvironmentObject into a view model to share data across your app. Here are the steps to achieve this:

  1. Create an Environment Object:
    • First, create an environment object that holds the data you want to share. You can do this by defining a class or struct that conforms to the ObservableObject protocol.
    • An example of an environment object might be a UserSettings object that tracks session data like whether a user is logged in or an access token.
  2. Inject the Environment Object into Your View:
    • In your SwiftUI view, use the @EnvironmentObject property wrapper to access the environment object.
    • For instance, if you have a UserSettings environment object, you can inject it into your view like this
struct YourView: View {
    @EnvironmentObject var settings: UserSettings
    @ObservedObject var viewModel = YourViewModel()

    var body: some View {
        VStack {
            Text("Hello")
            // Add other views here
        }
        .onAppear {
            self.viewModel.setup(self.settings)
        }
    }
}

Initialize Your View Model with the Environment Object:

  • In your view model (e.g., YourViewModel), create a property to hold the environment object (e.g., settings).
  • Implement a method (e.g., setup(_:)) that takes the environment object as a parameter and assigns it to the view model’s property.
class YourViewModel: ObservableObject {
    var settings: UserSettings?

    func setup(_ settings: UserSettings) {
        self.settings = settings
    }
}
  1. Considerations:
    • Be aware that using this approach, you’ll end up with optionals (since the environment object might not be available immediately).
    • Updates to the environment object won’t automatically trigger view updates unless you explicitly use @ObservedObject within your view model.

In SwiftUI, you can pass an EnvironmentObject into a view model by either injecting it directly into the view model\’s initializer or by using property injection. Here\’s how you can achieve both approaches:

Direct Injection:

In this approach, you inject the EnvironmentObject directly into the view model\’s initializer.

import SwiftUI

class MyViewModel: ObservableObject {
    @EnvironmentObject var userData: UserData

    // Your view model logic here...
}

struct MyView: View {
    @EnvironmentObject var userData: UserData
    @StateObject var viewModel = MyViewModel()

    var body: some View {
        // Use viewModel here
        Text("Hello, \\(viewModel.userData.username)")
    }
}

Property Injection:

In this approach, you pass the EnvironmentObject to the view model through a property setter.

import SwiftUI

class MyViewModel: ObservableObject {
    var userData: UserData?

    // Inject EnvironmentObject through a setter
    func inject(userData: UserData) {
        self.userData = userData
    }

    // Your view model logic here...
}

struct MyView: View {
    @EnvironmentObject var userData: UserData
    @StateObject var viewModel = MyViewModel()

    var body: some View {
        // Inject EnvironmentObject into viewModel
        Text("Hello, \\(userData.username)")
            .onAppear {
                viewModel.inject(userData: userData)
            }
    }
}

Both approaches have their pros and cons:

  • Direct Injection: This approach is simpler and more straightforward. However, it ties the view model directly to the EnvironmentObject, which may make it less reusable.
  • Property Injection: This approach allows for more flexibility and decoupling between the view model and the EnvironmentObject. However, it requires additional setup to inject the object into the view model.
Scroll to Top