Search code examples
swiftuiswiftui-navigationstack

SwiftUI EnvironmentObject passing in @StateObject vs creating instance inline causes different behaviour


I am passing EnvironmentObjects at the app level so that I can access them throughout the app. I am creating them in line like so:

var body: some Scene {
    WindowGroup {
        MainContentView()
            .environmentObject(NavigationStackManager())
            .environmentObject(CalendarVM())
    }
}

I would expect to have the same behaviour when I do this implementation:

@StateObject private var navigationManager = NavigationStackManager()

var body: some Scene {
        WindowGroup {
            MainContentView()
                .environmentObject(navigationManager)
                .environmentObject(CalendarVM())
        }
    }

However when I do the second implementation I get some strange states, namely subviews in the NavigationStack are reseting some of the properties.

The behaviour is as expected again, when I pass all of the @StatObjects in like so

@StateObject private var navigationManager = NavigationStackManager()
@StateObject private var calendarVM = CalendarVM()

var body: some Scene {
        WindowGroup {
            MainContentView()
                .environmentObject(navigationManager)
                .environmentObject(calendarVM)
        }
    }

I am trying to understand 1. what is the difference between the 3 implementations:)


Solution

  • From my perspective, I think the two first approaches are unsafe. And you might see that, somehow, the View didn't meet the gap and didn't re-render. So it still keeps the same instances. The right way to do is:

    @StateObject private var navigationManager = NavigationStackManager()
    @StateObject private var calendarVM = CalendarVM()
    
    var body: some Scene {
        WindowGroup {
            MainContentView()
                .environmentObject(navigationManager)
                .environmentObject(calendarVM)
        }
    }
    

    By this way, the entire app will keep the same instances of both NavigationStackManager and CalendarVM, instead of creating them again.