При сохранении основного объекта данных в popover в SwiftUI возникает ошибка nilError без повторной передачи .environment в SubView


15

Игра с SwiftUI и Core Data привела меня к любопытной проблеме. Итак, ситуация следующая:

У меня есть основной вид «AppView» и подвид с именем «SubView». Представление SubView будет открыто из представления AppView, если я нажму кнопку «плюс» на панели навигации NavigationTitleBar в виде всплывающего окна или листа.

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

Представление SubView имеет небольшую форму с двумя объектами TextField для добавления имени и фамилии. Входные данные этих двух объектов обрабатываются двумя отдельными свойствами @State. Третий объект в этой форме - простая кнопка, которая должна сохранить имя и фамилию в прикрепленном объекте клиента для 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")
}

Если я пытаюсь сохранить сущность Customer таким способом, я получаю ошибку: «nilError», в частности: «Неразрешенная ошибка Error Domain = Foundation._GenericObjCError Code = 0» (null) », [:]" из NSError.

Но после выяснения, что когда я добавляю .environment(\.managedObjectContext, context)в вызов SubView () примерно так, SubView().environment(\.managedObjectContext, context)он работает как шарм.

Кто-нибудь знает, почему мне нужно передать managedObjectContext во второй раз? Я подумал, что мне просто нужно передать managedObjectContext один раз, чтобы использовать его во всей иерархии представления, как в 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)

Это потому, что вызов SubView () таким образом, представление не является частью иерархии представления? Я не понимаю это ...


1
Я наблюдал такое же поведение на iOS 13.1. Xcode 11.1
— Арун Патра

Вы не первый, кто обнаружил эту проблему, я решил ее, передав контекст в качестве параметра. Надеюсь, Apple исправит это в ближайшее время.
— Майкл Салмон

1
Как и ожидалось, это ошибка в компиляторе Swift / SwiftUI. Харлан Хаскинс из Apple дал мне подтверждение этому: bugs.swift.org/browse/SR-11607 - так что я надеюсь, что это будет исправлено в ближайшее время. Для быстрого исправления: Передача .environment (\. ManagedObjectContext, context) во всплывающее окно SubView работает.
— lukas_nitaco

Ответы:


24

ВАУ ЭТО ПОБЕЛА МЕНЯ ОРЕХАМИ! Тем более, что ошибки сообщают вам абсолютно никакой информации о том, как исправить.

Вот исправление, пока ошибка в XCode не будет решена:

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

Просто добавьте .environment(\.managedObjectContext, managedObjectContext)к вашему вторичному представлению (модальный, в этом примере).


8
огромная помощь для всех нас, достаточно смелых, чтобы развиваться в SwiftUI прямо сейчас ...
— Apostolos Apostolidis

Решил и мою проблему. Спасибо.
— P. Ent

1
Мой друг! Почему SwiftUI делает это необходимым? Окружающая среда должна быть доступна во всем мире.
— pulse4life

Но зачем это нужно? Действительно странно, что SwiftUI не делает это автоматически ...
— Loris Foe

Это необходимо, потому что это единственное решение проблемы сейчас. Apple, очевидно, работает над исправлением. Помните, что SwiftUI все еще очень новый.
— stardust4891
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.