swiftmacosswiftuistate

How to avoid sharing state on WindowGroup / multiscreen macOS with SwiftUI?


I am building a multiplatform app for iOS/iPadOS/macOS and would like to be able to open multiple windows of the same application on macOS.

This feature comes out of the box when you use WindowGroup and I'm able to open a new window from the status bar. However, I'm having trouble with separating state that should be shared and state that should be local to the windows.

Here's a stripped down version of my current app entry point. When opening a new window, I would like to ensure that the api state object is shared across all opened windows, but the navManager object should maintain it's own state per opened Window.


import SwiftUI

@Observable class NavManager {
    enum NavItem {
        case a
        case b
    }
    
    var currentNav: NavItem = .a
}

@Observable class Api {
    var someProperty: String = "Hello World"
}


struct NavigationView: View {
    @State private var navManager: NavManager = NavManager()
    
    var body: some View {
        switch navManager.currentNav {
        case .a:
            Text("Navigated to a")
        case .b:
            Text("Navigated to b")
        }
        Button {
            if navManager.currentNav == .a {
                navManager.currentNav = .b
            } else {
                navManager.currentNav = .a
            }
        } label: {
            Text("Toggle navigation")
        }
        Text("Some subview hierarchy that needs navManager")
            .environment(navManager)
    }
}

@main
struct MPFApp: App {
    
    @State private var api: Api = Api()
    
    var body: some Scene {
        WindowGroup {
            NavigationView()
                .environment(api)
        }
    }
}

Unfortunately with this code the state maintained in navManager is still shared between both windows, meaning navigation in one, will automatically navigate in the other window.

I couldn't find a clear description for this on the apple website or their WWDC talks. Any help would be much appreciated!

Kind regards, Thiezn

UPDATE: This functionality is now working properly. Ensure not to initialize the NavManager in your App view, but initialize it inside of NavigationView.


Solution

  • This functionality is now working properly. Ensure not to initialize the NavManager in your App view, but initialize it inside of NavigationView.