Saving core data entity in popover in SwiftUI thro

2020-02-28 07:10发布

问题:

Playin' with SwiftUI and Core Data brought me into a curious problem. So the situation is the following:

I have a main view "AppView" and a sub view named "SubView". The SubView view will be opened from the AppView view if I click the plus button in the NavigationTitleBar as popover or sheet.

@Environment(\.managedObjectContext) var managedObjectContext
@State private var modal: Bool = false
...
Button(action: {
        self.modal.toggle()
      }) {
        Image(systemName: "plus")
      }.popover(isPresented: self.$modal){
        SubView()
      }

The SubView view has a little form with two TextField objects to add a forename and a surname. The inputs of this two objects are handled by two separate @State properties. The third object in this form is simple button, which should save a the fore- and surname to an attached Customer Entity for CoreData.

...
@Environment(\.managedObjectContext) var managedObjectContext
...
Button(action: {
  let customerItem = Customer(context: self.managedObjectContext)
  customerItem.foreName = self.forename
  customerItem.surname = self.surname

  do {
    try self.managedObjectContext.save()
  } catch {
    print(error)
  }
}) {
  Text("Speichern")
}

If I try to save the Customer entity this way, I get the error: "nilError", specially: "Unresolved error Error Domain=Foundation._GenericObjCError Code=0 "(null)", [:]" from NSError.

But after figuring out, that when I add .environment(\.managedObjectContext, context) to the SubView() call like so SubView().environment(\.managedObjectContext, context) it's works like a charm.

Does anyone know, why I need to pass the managedObjectContext a second time? I thought, that I just need to pass the managedObjectContext one time to use it in the whole view hierarchy, like in the SceneDelegate.swift:

    // Get the managed object context from the shared persistent container.
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

    // Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath.
    // Add `@Environment(\.managedObjectContext)` in the views that will need the context.
    let contentView = AppView().environment(\.managedObjectContext, context)

Is it because calling the SubView() this way, the view is not part of the view hierarchy? I don't understand it...

回答1:

WOW THIS DROVE ME NUTS! Especially because the errors tells you absolutely no information as to how to fix.

Here is the fix until the bug in Xcode is resolved:

        .navigationBarItems(trailing:
            Button(action: {
                self.add = true
            }, label: {
                Text("Add Todo List")
            }).sheet(isPresented: $add, content: {
                AddTodoListView().environment(\.managedObjectContext, managedObjectContext)
            })
        )

Just add .environment(\.managedObjectContext, managedObjectContext) to your secondary view (a Modal, in this example).