Question

How to share the same model container between WindowGroup and MenuBarExtra in SwiftUI?

I am working on a SwiftUI application where I need to share the same model container between a WindowGroup and a MenuBarExtra. The goal is to have both components update in sync without needing to restart the app.

import SwiftData

@main
struct DeployApp: App {
    @AppStorage("folderPaths") var folderPaths: [String]?
    @Environment(\.modelContext) private var modelContext
    
    var body: some Scene {
        WindowGroup(id: "settings-window") {
            ContentView()
        }
        .modelContainer(for: Project.self)
        
        MenuBarExtra {
            MenuView()
                .modelContainer(for: Project.self)
        } label: {
            Image(systemName: "swift")
        }
        .menuBarExtraStyle(.menu)
    }
}

Problem:

The issue I am facing is that updates only occur in the MenuBar (or vice versa) after closing and reopening the app. I want both WindowGroup and MenuBarExtra to reflect changes immediately and remain in sync.

Expected Result:

Both WindowGroup and MenuBarExtra should use the same model container and update their views in real-time without requiring an app restart.

Actual Result:

Currently, updates in the model are only reflected in either the WindowGroup or the MenuBarExtra after closing and reopening the app.

Error Messages:

There are no explicit error messages, but the synchronization issue is evident in the behavior of the UI components.

What I've Tried:

Ensuring both WindowGroup and MenuBarExtra use .modelContainer(for: Project.self). Searching online for solutions related to SwiftUI model container sharing between different scenes. Experimenting with different ways to initialize and share the model container. Despite these efforts, the problem persists, and I have not found a solution that allows both WindowGroup and MenuBarExtra to update in sync.

Research:

I have looked into various resources on SwiftUI and model containers, but most examples do not cover the specific case of sharing a model container between a WindowGroup and a MenuBarExtra.

How can I ensure that both WindowGroup and MenuBarExtra use the same model container and update properly without needing to restart the app?

 2  35  2
1 Jan 1970

Solution

 3

Thanks to the comment: "Put the container in a variable they can both access. The basic code Xcode provides in a new project is a good example." – lorem ipsum

The following code shows how to initialize a shared ModelContainer and use it in both WindowGroup and MenuBarExtra:

import SwiftData

@main
struct DeployApp: App {
    let container: ModelContainer
    
    init() {
        do {
            container = try ModelContainer(for: Project.self)
        } catch {
            fatalError("Failed to initialize ModelContainer: \(error)")
        }
    }
    
    var body: some Scene {
        WindowGroup(id: "settings-window") {
            ContentView()
        }
        .modelContainer(container)
        
        MenuBarExtra {
            MenuView()
                .modelContainer(container)
        } label: {
            Image(systemName: "swift")
        }
        .menuBarExtraStyle(.menu)
    }
}

This ensures that both WindowGroup and MenuBarExtra are using the same instance of ModelContainer, allowing them to stay in sync.

2024-07-22
Lucas Buchalla Sesti