En un SwiftUI, View
tengo una List
base para @FetchRequest
mostrar los datos de una Primary
entidad y la Secondary
entidad conectada a través de la relación . El View
y List
se actualiza correctamente cuando agrego una nueva Primary
entidad con una nueva entidad secundaria relacionada.
El problema es que cuando actualizo el Secondary
elemento conectado en una vista detallada, la base de datos se actualiza, pero los cambios no se reflejan en la Primary
Lista. Obviamente, el @FetchRequest
no se activa por los cambios en otra Vista.
Cuando agrego un nuevo elemento en la vista principal a partir de entonces, el elemento previamente modificado finalmente se actualiza.
Como solución alternativa, actualizo adicionalmente un atributo de la Primary
entidad en la vista de detalles y los cambios se propagan correctamente a la Primary
Vista.
Mi pregunta es: ¿Cómo puedo forzar una actualización en todo lo relacionado @FetchRequests
con SwiftUI Core Data? Especialmente, cuando no tengo acceso directo a las entidades relacionadas / @Fetchrequests
?
import SwiftUI
extension Primary: Identifiable {}
// Primary View
struct PrimaryListView: View {
@Environment(\.managedObjectContext) var context
@FetchRequest(
entity: Primary.entity(),
sortDescriptors: [NSSortDescriptor(key: "primaryName", ascending: true)]
)
var fetchedResults: FetchedResults<Primary>
var body: some View {
List {
ForEach(fetchedResults) { primary in
NavigationLink(destination: SecondaryView(primary: primary)) {
VStack(alignment: .leading) {
Text("\(primary.primaryName ?? "nil")")
Text("\(primary.secondary?.secondaryName ?? "nil")").font(.footnote).foregroundColor(.secondary)
}
}
}
}
.navigationBarTitle("Primary List")
.navigationBarItems(trailing:
Button(action: {self.addNewPrimary()} ) {
Image(systemName: "plus")
}
)
}
private func addNewPrimary() {
let newPrimary = Primary(context: context)
newPrimary.primaryName = "Primary created at \(Date())"
let newSecondary = Secondary(context: context)
newSecondary.secondaryName = "Secondary built at \(Date())"
newPrimary.secondary = newSecondary
try? context.save()
}
}
struct PrimaryListView_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
return NavigationView {
PrimaryListView().environment(\.managedObjectContext, context)
}
}
}
// Detail View
struct SecondaryView: View {
@Environment(\.presentationMode) var presentationMode
var primary: Primary
@State private var newSecondaryName = ""
var body: some View {
VStack {
TextField("Secondary name:", text: $newSecondaryName)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
.onAppear {self.newSecondaryName = self.primary.secondary?.secondaryName ?? "no name"}
Button(action: {self.saveChanges()}) {
Text("Save")
}
.padding()
}
}
private func saveChanges() {
primary.secondary?.secondaryName = newSecondaryName
// TODO: ❌ workaround to trigger update on primary @FetchRequest
primary.managedObjectContext.refresh(primary, mergeChanges: true)
// primary.primaryName = primary.primaryName
try? primary.managedObjectContext?.save()
presentationMode.wrappedValue.dismiss()
}
}
ObservableObject
?