0

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:)

2
  • 1
    It is never safe to create objects on the body StateObject is safe because it gets storage within SwiftUI instead of being recreated. SwiftUI can create/recreate structures at anytime. Commented Jan 29, 2024 at 11:07
  • 1
    @StateObject means call body when any of the @Published properties change. Since your body doesn't use any of the properties it means you've got it in the wrong place in the View hierarchy. body is called needlessly in this example code. Commented Jan 29, 2024 at 17:45

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.