Estou achando impossível usar dados principais com o SwiftUI, porque, como passo os dados principais para uma variável de objeto observada, a visualização do link de navegação manterá uma referência ao objeto mesmo depois que a visualização desaparecer, assim que eu excluir o objeto do contexto, o aplicativo falha, sem mensagens de erro.
Confirmei isso envolvendo a variável do objeto de dados do núcleo em um modelo de exibição como opcional e, em seguida, defina o objeto nulo logo após a ação de exclusão de contexto e o aplicativo funcione bem, mas isso não é uma solução, pois preciso do objeto de dados do núcleo vincular-se às visões rápidas da interface do usuário e ser a fonte da verdade. Como isso deve funcionar? Eu realmente não posso fazer nada remotamente complexo com o SwiftUI, ao que parece.
Tentei atribuir o objeto de dados principais passados a um @State opcional, mas isso não funciona. Não consigo usar o @Binding porque é um objeto buscado. E não posso usar uma variável, pois os controles swiftui exigem ligações. Só faz sentido usar um @ObservedObject, mas isso não pode ser opcional, o que significa que, quando o objeto atribuído a ele é excluído, o aplicativo falha, porque não consigo defini-lo como nulo.
Aqui está o objeto de dados principal, que é um objeto observável por padrão:
class Entry: NSManagedObject, Identifiable {
@NSManaged public var date: Date
}
Aqui está uma visão que passa um objeto de entrada de dados principal para outra visão.
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])
}
}
}
}
}
}
Agora, aqui está a visualização que acessa todos os atributos do objeto principal de entrada de dados que foi passado. Depois que eu excluo esta entrada, de qualquer visualização, a propósito, ela ainda é referenciada aqui e faz com que o aplicativo falhe imediatamente. Acredito que isso também tenha algo a ver com o link de navegação que inicializa todas as visualizações de destino antes mesmo de serem acessadas. O que não faz sentido por que isso faria isso. Isso é um bug ou existe uma maneira melhor de conseguir isso?
Eu até tentei fazer a exclusão onDisappear sem sucesso. Mesmo se eu excluir o JournalView, ele continuará travando, pois o NavigationLink ainda fará referência ao objeto. Interessante não travará se excluir um NavigationLink que ainda não foi clicado.
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")
}
}
}
}
ATUALIZAR
A falha está me levando ao primeiro uso da entrada no EntryView e lê o Thread 1: EXC_BAD_INSTRUCTION (código = EXC_I386_INVOP, subcode = 0x0) .. essa é a única mensagem emitida.
A única solução possível é adicionar uma propriedade ao objeto de dados principal "isDeleted" e defini-la como true em vez de tentar excluir do contexto. Então, quando o aplicativo é encerrado, ou ao iniciar, posso limpar e excluir todas as entradas excluídas? Não é o ideal e prefere descobrir o que está errado aqui, pois parece que não estou fazendo nada diferente do exemplo do MasterDetailApp, que parece funcionar.
Respostas:
Eu basicamente tive o mesmo problema. Parece que o SwiftUI carrega todas as visualizações imediatamente, portanto, a visualização foi carregada com as propriedades do objeto CoreData existente. Se você excluí-lo na Visualização onde alguns dados são acessados via @ObservedObject, eles travarão.
Minha solução alternativa:
Você precisa definir um Notification.name, como:
Um pouco hacky, mas isso funciona para mim.
fonte
Encontrei o mesmo problema e realmente não encontrei uma solução para o problema raiz. Mas agora "protejo" a exibição que usa os dados referenciados como este:
Isso também parece hacky, mas funciona bem por enquanto. É menos complexo do que usar uma notificação para "adiar" a exclusão, mas ainda assim graças aos sTOOs, responda a dica com
.isFault
!fonte