Salvar a entidade de dados principal no popover no SwiftUI lança nilError sem passar o .environment para o SubView novamente

15

Brincar com SwiftUI e Core Data me trouxe um problema curioso. Portanto, a situação é a seguinte:

Eu tenho uma vista principal "AppView" e uma sub-vista denominada "SubView". A exibição do SubView será aberta na exibição do AppView se eu clicar no botão de adição no NavigationTitleBar como popover ou planilha.

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

A exibição do SubView possui um pequeno formulário com dois objetos TextField para adicionar um nome e sobrenome. As entradas desses dois objetos são tratadas por duas propriedades @State separadas. O terceiro objeto neste formulário é o botão simples, que deve salvar o nome e o sobrenome em uma Entidade do Cliente anexada para 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")
}

Se eu tentar salvar a entidade Cliente dessa maneira, recebo o erro: "nilError", especialmente: "Erro não resolvido Erro Domínio = Foundation._GenericObjCError Code = 0" (null) ", [:]" do NSError.

Mas depois de descobrir, que quando adiciono .environment(\.managedObjectContext, context)à chamada SubView () assim SubView().environment(\.managedObjectContext, context)funciona como um encanto.

Alguém sabe, por que eu preciso passar o managedObjectContext uma segunda vez? Eu pensei que só precisava passar o managedObjectContext uma vez para usá-lo em toda a hierarquia de exibição, como no 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)

É porque, ao chamar o SubView () dessa maneira, a exibição não faz parte da hierarquia da exibição? Eu não entendo ...

lukas_nitaco
fonte
11
Eu observei o mesmo comportamento no iOS 13.1. Xcode 11.1
Arun Patra
Você não é o primeiro a encontrar esse problema, resolvi-o passando o contexto como parâmetro. Espero que a Apple conserte isso em breve.
Michael Salmon
11
Como esperado, isso parece ser um bug no Compilador do Swift / SwiftUI. Então Harlan Haskins da Apple me deu a confirmação para isso: bugs.swift.org/browse/SR-11607 - Então, espero que isso seja corrigido em breve. Para a solução rápida: Passar .environment (\. ManagedObjectContext, context) para o popover SubView funciona.
Lukas_nitaco 15/10/19

Respostas:

24

WOW ISSO ME DESLOCOU NOZES! Especialmente porque os erros não informam absolutamente nenhuma informação sobre como corrigir.

Aqui está a correção até que o bug no Xcode seja resolvido:

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

Basta adicionar .environment(\.managedObjectContext, managedObjectContext)à sua visão secundária (um Modal, neste exemplo).

kdion4891
fonte
8
grande ajuda para todos nós corajoso o suficiente para se desenvolver em SwiftUI agora ...
Apostolos Apostolidis
Resolvi meu problema também. Obrigado.
P. Ent
11
Meu cara! Por que o SwiftUI torna isso necessário? O ambiente deve ser acessado globalmente.
pulse4life
Mas por que isso é necessário? Realmente estranho que o SwiftUI não o faça automaticamente ...
Loris Foe
É necessário porque é a única solução para o bug no momento. Aparentemente, a Apple está trabalhando em uma correção. Lembre-se de que o SwiftUI ainda é muito novo.
stardust4891