swiftuiobservedobjectenvironmentobject

EnvironmentObject causes unrelated ObservedObject to reset


I am not quite sure I understand what is going on here as I am experimenting with an EnvironmentObject in SwiftUI.

I recreated my problem with a small example below, but to summarize: I have a ContentView, ContentViewModel, and a StateController. The ContentView holds a TextField that binds with the ContentViewModel. This works as expected. However, if I update a value in the StateController (which to me should be completely unrelated to the ContentViewModel) the text in the TextField is rest.

Can someone explain to me why this is happening, and how you could update a state on an EnvironmentObject without having SwiftUI redraw unrelated parts?

App.swift

@main
struct EnvironmentTestApp: App {

    @ObservedObject var stateController = StateController()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(stateController)
        }
    }
}

ContentView.swift

struct ContentView: View {

    @ObservedObject private var viewModel = ContentViewModel()
    @EnvironmentObject private var stateController: StateController

    var body: some View {
        HStack {
            TextField("Username", text: $viewModel.username)
            Button("Update state") {
                stateController.validated = true
            }
        }

    }
}

ContentViewModel.swift

class ContentViewModel: ObservableObject {
    @Published var username = ""
}

StateController.swift

class StateController: ObservableObject {
    @Published var validated = false
}

Solution

  • Like lorem-ipsum pointed out, you should use @StateObject.

    A good rule of thumb is to use @StateObject every time you init a viewModel, but use @ObservedObject when you are passing in a viewModel that has already been init.