Marcos Tanaka
Marcos Tanaka

Reputation: 3336

Access managedObjectContext to execute a @ FetchRequest in the @main app

I'm creating a SwiftUI macOS app with a dynamic menu item list that will be created based on the user's data:

enter image description here

Here's how I'm trying to create the menu:

@main
struct MacOSApp: App {

    @AppStorage("tagFilter") private var tagFilter: String = ""

    @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Tag.name, ascending: true)], animation: .default)
    private var tags: FetchedResults<Tag>

    var body: some Scene {
        WindowGroup {
            ContentView(menuBarActionsState: menuBarActionsState)
                .environment(\.managedObjectContext, storageProvider.persistentContainer.viewContext)
        }.commands {
            CommandGroup(before: CommandGroupPlacement.toolbar) {
                Picker("Filter by Tag", selection: $tagFilter) {
                    ForEach(tags, id: \.self) { tag in
                        Text(tag.name ?? "").tag(tag.id ?? "")
                    }
                }
            }
        }
    }
}

The problem is, I don't have a managedObjectContext in the @main app, as this is the starting point of the application. It is injected into the environment of the ContentView, but the menu is created above that.

Because I don't have a managedObjectContext, the following error happens at runtime:

Context in environment is not connected to a persistent store coordinator:  <NSManagedObjectContext: 0x6000039a2700>

Can we access the managedObjectContext in the @main app level? Or can I inject a managedObjectContext in my @FetchRequest somehow, so I can use it in the @main app to build the menu?

Upvotes: 0

Views: 69

Answers (1)

malhal
malhal

Reputation: 30567

Break up your View data structs to be as small as possible based on the vars they use. It's called having a tight invalidation and should resolve the problem.

@main
struct MacOSApp: App {

    var body: some Scene {
        WindowGroup {
            ContentView(menuBarActionsState: menuBarActionsState)
                .environment(\.managedObjectContext, storageProvider.persistentContainer.viewContext)
        }.commands {
            CommandGroup(before: CommandGroupPlacement.toolbar) {
                TagsView()
            }
            .environment(\.managedObjectContext, storageProvider.persistentContainer.viewContext)
        }
    }
}


struct TagsView: View {
    @AppStorage("tagFilter") private var tagFilter: String = ""

    @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Tag.name, ascending: true)], animation: .default)
    private var tags: FetchedResults<Tag>

    var body: some View {
         Picker("Filter by Tag", selection: $tagFilter) {
             ForEach(tags, id: \.self) { tag in
                 Text(tag.name ?? "").tag(tag.id ?? "")
             }
         }
    }
}

Upvotes: 2

Related Questions