Durch das Speichern der Kerndatenentität in Popover in SwiftUI wird nilError ausgelöst, ohne dass .environment erneut an SubView übergeben wird

15

Das Spielen mit SwiftUI und Core Data brachte mich in ein merkwürdiges Problem. Die Situation ist also wie folgt:

Ich habe eine Hauptansicht "AppView" und eine Unteransicht mit dem Namen "SubView". Die SubView-Ansicht wird in der AppView-Ansicht geöffnet, wenn ich in der NavigationTitleBar als Popover oder Blatt auf die Plus-Schaltfläche klicke.

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

Die SubView-Ansicht hat ein kleines Formular mit zwei TextField-Objekten, um einen Vor- und einen Nachnamen hinzuzufügen. Die Eingaben dieser beiden Objekte werden von zwei separaten @ State-Eigenschaften verarbeitet. Das dritte Objekt in diesem Formular ist eine einfache Schaltfläche, mit der Vor- und Nachname für CoreData in einer angehängten Kundenentität gespeichert werden sollen.

...
@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")
}

Wenn ich versuche, die Kundenentität auf diese Weise zu speichern, erhalte ich den Fehler "nilError", insbesondere: "Ungelöster Fehler Fehler Domain = Foundation._GenericObjCError Code = 0" (null) ", [:]" von NSError.

Aber nachdem ich herausgefunden habe, dass, wenn ich .environment(\.managedObjectContext, context)zum SubView () -Aufruf hinzufüge , soSubView().environment(\.managedObjectContext, context) wie ein Zauber wirkt.

Weiß jemand, warum ich den manageObjectContext ein zweites Mal übergeben muss? Ich dachte, dass ich den manageObjectContext nur einmal übergeben muss, um ihn in der gesamten Ansichtshierarchie zu verwenden, wie in 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)

Liegt es daran, dass die Ansicht nicht Teil der Ansichtshierarchie ist, weil SubView () auf diese Weise aufgerufen wird? Ich verstehe es nicht ...

lukas_nitaco
quelle
1
Ich habe das gleiche Verhalten unter iOS 13.1 beobachtet. Xcode 11.1
Arun Patra
Sie sind nicht die Ersten, die dieses Problem finden. Ich habe es gelöst, indem ich den Kontext als Parameter übergeben habe. Hoffentlich wird Apple es bald beheben.
Michael Salmon
1
Wie erwartet scheint dies ein Fehler im Compiler von Swift / SwiftUI zu sein. Also gab mir Harlan Haskins von Apple die Bestätigung dafür: bugs.swift.org/browse/SR-11607 - Ich hoffe, dass dies bald behoben wird. Für die schnelle Lösung: Das Übergeben von .environment (\. ManagedObjectContext, context) an das SubView-Popover funktioniert.
lukas_nitaco

Antworten:

24

WOW DAS DROVE ME NUTS! Vor allem, weil die Fehler Ihnen absolut keine Informationen darüber geben, wie Sie sie beheben können.

Hier ist das Update, bis der Fehler in Xcode behoben ist:

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

Fügen .environment(\.managedObjectContext, managedObjectContext)Sie einfach Ihre sekundäre Ansicht hinzu (in diesem Beispiel ein Modal).

kdion4891
quelle
8
immense Hilfe für uns alle, die mutig genug sind, uns jetzt in SwiftUI zu entwickeln ...
Apostolos Apostolidis
Ich habe auch mein Problem gelöst. Vielen Dank.
P. Ent
1
Mein Kumpel! Warum macht SwiftUI dies notwendig? Auf die Umgebung sollte global zugegriffen werden.
Puls4life
Aber warum ist es notwendig? Wirklich seltsam, dass SwiftUI es nicht automatisch schafft ...
Loris Foe
Es ist notwendig, weil es derzeit die einzige Lösung für den Fehler ist. Apple arbeitet anscheinend an einem Fix. Denken Sie daran, SwiftUI ist noch sehr neu.
stardust4891