L'enregistrement de l'entité de données principale dans un popover dans SwiftUI lève nilError sans transmettre à nouveau .environment à SubView

15

Jouer avec SwiftUI et Core Data m'a posé un curieux problème. La situation est donc la suivante:

J'ai une vue principale "AppView" et une vue secondaire nommée "SubView". La vue SubView sera ouverte à partir de la vue AppView si je clique sur le bouton plus dans le NavigationTitleBar en tant que popover ou feuille.

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

La vue SubView a une petite forme avec deux objets TextField pour ajouter un prénom et un nom de famille. Les entrées de ces deux objets sont gérées par deux propriétés @State distinctes. Le troisième objet de ce formulaire est un simple bouton, qui devrait enregistrer le prénom et le nom de famille dans une entité client attachée pour 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")
}

Si j'essaie d'enregistrer l'entité Client de cette façon, j'obtiens l'erreur: "nilError", spécialement: "Erreur non résolue Error Domain = Foundation._GenericObjCError Code = 0" (null) ", [:]" de NSError.

Mais après avoir compris, que lorsque j'ajoute .environment(\.managedObjectContext, context)à l'appel SubView (), SubView().environment(\.managedObjectContext, context)cela fonctionne comme un charme.

Est-ce que quelqu'un sait pourquoi je dois passer le managedObjectContext une deuxième fois? Je pensais que j'avais juste besoin de passer le managedObjectContext une fois pour l'utiliser dans toute la hiérarchie des vues, comme dans 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)

Est-ce parce que l'appel de SubView () de cette façon, la vue ne fait pas partie de la hiérarchie des vues? Je ne comprends pas ...

lukas_nitaco
la source
1
J'ai observé le même comportement sur iOS 13.1. Xcode 11.1
Arun Patra
Vous n'êtes pas le premier à trouver ce problème, je l'ai résolu en passant le contexte comme paramètre. Espérons qu'Apple le corrigera bientôt.
Michael Salmon
1
Comme prévu, cela semble être un bogue dans le compilateur de Swift / SwiftUI. Harlan Haskins d'Apple m'a donc confirmé cela: bugs.swift.org/browse/SR-11607 - J'espère donc que ce sera corrigé bientôt. Pour la solution rapide: le passage de .environment (\. ManagedObjectContext, context) aux fenêtres contextuelles SubView fonctionne.
lukas_nitaco

Réponses:

24

WOW CECI NOUS ENCOURAGE! Surtout parce que les erreurs ne vous indiquent absolument aucune information sur la façon de résoudre le problème.

Voici le correctif jusqu'à ce que le bogue dans Xcode soit résolu:

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

Ajoutez simplement .environment(\.managedObjectContext, managedObjectContext)à votre vue secondaire (un modal, dans cet exemple).

kdion4891
la source
8
une aide immense pour nous tous assez courageux pour nous développer dans SwiftUI en ce moment ...
Apostolos Apostolidis
J'ai également résolu mon problème. Je vous remercie.
P. Ent
1
Mon mec! Pourquoi SwiftUI rend-il cela nécessaire? L'environnement doit être accessible à l'échelle mondiale.
pulse4life
Mais pourquoi est-ce nécessaire? Vraiment étrange que SwiftUI ne le fasse pas automatiquement ...
Loris Foe
C'est nécessaire car c'est la seule solution au bug en ce moment. Apple travaille apparemment sur un correctif. N'oubliez pas que SwiftUI est encore très nouveau.
stardust4891