Me resulta imposible usar datos centrales con SwiftUI, porque cuando paso datos centrales a una variable de objeto de vista observada, la vista del enlace de navegación mantendrá una referencia al objeto incluso después de que la vista haya desaparecido, tan pronto como elimine el objeto del contexto, la aplicación se bloquea, sin mensajes de error.
He confirmado esto envolviendo la variable del objeto de datos centrales en un modelo de vista como opcional, luego configuré el objeto como nulo justo después de la acción de eliminación de contexto y la aplicación funciona bien, pero esto no es una solución porque necesito el objeto de datos central para unirse a las rápidas opiniones de la interfaz de usuario y ser la fuente de la verdad. ¿Cómo se supone que esto funciona? Parece que no puedo hacer nada remotamente complejo con SwiftUI.
He intentado asignar el objeto de datos básicos pasado a un @State opcional, pero esto no funciona. No puedo usar @Binding porque es un objeto recuperado. Y no puedo usar una variable, ya que los controles swiftui requieren enlaces. Solo tiene sentido usar un @ObservedObject, pero esto no puede ser opcional, lo que significa que cuando se elimina el objeto asignado, la aplicación se bloquea porque no puedo configurarlo en cero.
Aquí está el objeto de datos básicos, que es un objeto observable por defecto:
class Entry: NSManagedObject, Identifiable {
@NSManaged public var date: Date
}
Aquí hay una vista que pasa un objeto de entrada de datos central a otra vista.
struct JournalView: View {
@Environment(\.managedObjectContext) private var context
@FetchRequest(
entity: Entry.entity(),
sortDescriptors: [],
predicate: nil,
animation: .default
) var entries: FetchedResults<Entry>
var body: some View {
NavigationView {
List {
ForEach(entries.indices) { index in
NavigationLink(destination: EntryView(entry: self.entries[index])) {
Text("Entry")
}
}.onDelete { indexSet in
for index in indexSet {
self.context.delete(self.entries[index])
}
}
}
}
}
}
Ahora aquí está la vista que accede a todos los atributos del objeto de entrada de datos central que se pasó. Una vez, elimino esta entrada, por cierto, todavía se hace referencia aquí y hace que la aplicación se bloquee de inmediato. Creo que esto también tiene algo que ver con el Enlace de navegación que inicializa toda la vista de destino incluso antes de acceder a ellos. Lo que no tiene sentido por qué haría eso. ¿Es esto un error o hay una mejor manera de lograrlo?
Incluso he intentado hacer la eliminación enDisappear sin éxito. Incluso si hago la eliminación de JournalView, se bloqueará ya que NavigationLink todavía hace referencia al objeto. Es interesante que no se bloquee si elimina un NavigationLink en el que aún no se ha hecho clic.
struct EntryView: View {
@Environment(\.managedObjectContext) private var context
@Environment(\.presentationMode) private var presentationMode
@ObservedObject var entry: Entry
var body: some View {
Form {
DatePicker(selection: $entry.date) {
Text("Date")
}
Button(action: {
self.context.delete(self.entry)
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Delete")
}
}
}
}
ACTUALIZAR
El bloqueo me está llevando al primer uso de la entrada en EntryView y lee el Tema 1: EXC_BAD_INSTRUCTION (código = EXC_I386_INVOP, subcódigo = 0x0) ... ese es el único mensaje lanzado.
La única solución que se me ocurre es agregar una propiedad al objeto de datos central "isDeleted" y establecerlo en verdadero en lugar de intentar eliminarlo del contexto. Luego, cuando la aplicación se cierra o se inicia, ¿puedo limpiar y eliminar todas las entradas que se han eliminado? No es ideal, y preferiría averiguar qué está mal aquí, ya que parece que no estoy haciendo nada diferente a la muestra MasterDetailApp, que parece funcionar.
Respuestas:
Básicamente tuve el mismo problema. Parece que SwiftUI carga cada vista inmediatamente, por lo que la vista se ha cargado con las Propiedades del Objeto CoreData existente. Si lo elimina dentro de la Vista donde se accede a algunos datos a través de @ObservedObject, se bloqueará.
Mi solución alternativa:
Debe definir un Notification.name, como:
Un poco hacky, pero esto funciona para mí.
fuente
Encontré el mismo problema y realmente no encontré una solución al problema raíz. Pero ahora "protejo" la vista que usa los datos referenciados como este:
Eso también se siente hacky, pero funciona bien por ahora. ¡Es menos complejo que usar una notificación para "diferir" la eliminación, pero aún así, gracias a la respuesta de sTOO por la pista
.isFault
!fuente