Dalam SwiftUI View
saya memiliki List
berdasarkan pada @FetchRequest
menunjukkan data suatu Primary
entitas dan hubungan yang terhubung Secondary
entitas. The View
dan yang List
diperbarui dengan benar, ketika saya menambahkan baru Primary
entitas dengan entitas sekunder terkait baru.
Masalahnya adalah, ketika saya memperbarui Secondary
item yang terhubung dalam tampilan detail, database akan diperbarui, tetapi perubahannya tidak tercermin dalam Primary
Daftar. Jelas, @FetchRequest
itu tidak dipicu oleh perubahan di tampilan lain.
Ketika saya menambahkan item baru di tampilan utama setelahnya, item yang sebelumnya diubah akhirnya diperbarui.
Sebagai solusinya, saya juga memperbarui atribut Primary
entitas dalam tampilan detail dan perubahan menyebar dengan benar ke tampilan Primary
.
Pertanyaan saya adalah: Bagaimana saya bisa memaksa pembaruan pada semua yang terkait @FetchRequests
dalam Data Inti SwiftUI? Terutama, ketika saya tidak memiliki akses langsung ke entitas terkait / @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
?Jawaban:
Anda memerlukan Penerbit yang akan menghasilkan acara tentang perubahan dalam konteks dan beberapa variabel status dalam tampilan utama untuk memaksa tampilan dibangun kembali saat menerima acara dari penerbit itu.
Penting: variabel keadaan harus digunakan dalam kode pembangun tampilan, jika tidak mesin rendering tidak akan tahu bahwa ada sesuatu yang berubah.
Berikut ini adalah modifikasi sederhana dari bagian yang terpengaruh dari kode Anda, yang memberikan perilaku yang Anda butuhkan.
sumber
RefreshView(toggle: Bool)
dengan EmptyView tunggal di tubuhnya. MenggunakanList {...}.background(RefreshView(toggle: self.refreshing))
akan berhasil.Saya mencoba menyentuh objek utama dalam tampilan detail seperti ini:
Kemudian daftar utama akan diperbarui. Tetapi tampilan detail harus tahu tentang objek induk. Ini akan berhasil, tetapi ini mungkin bukan cara SwiftUI atau Gabungkan ...
Edit:
Berdasarkan solusi di atas, saya memodifikasi proyek saya dengan fungsi save global (managedObject :). Ini akan menyentuh semua Entitas terkait, sehingga memperbarui semua @ FetchRequest yang relevan.
sumber