问题描述
在 SwiftUI View
我有一个基于 @FetchRequest
的 List
显示 Primary
实体的数据和通过关系连接 Secondary
实体.View
及其 List
正确更新,当我添加一个新的 Primary
实体和一个新的相关次要实体时.
In a SwiftUI View
i have a List
based on @FetchRequest
showing data of a Primary
entity and the via relationship connected Secondary
entity.The View
and its List
is updated correctly, when I add a new Primary
entity with a new related secondary entity.
问题是,当我在详细视图中更新连接的 Secondary
项时,数据库会更新,但更改未反映在 Primary
列表中.显然,@FetchRequest
不会被另一个视图中的更改触发.
The problem is, when I update the connected Secondary
item in a detail view, the database gets updated, but the changes are not reflected in the Primary
List.Obviously, the @FetchRequest
does not get triggered by the changes in another View.
此后当我在主视图中添加新项目时,之前更改的项目最终会得到更新.
When I add a new item in the primary view thereafter, the previously changed item gets finally updated.
作为一种变通方法,我在详细视图中另外更新了 Primary
实体的属性,并将更改正确传播到 Primary
视图.
As a workaround, i additionally update an attribute of the Primary
entity in the detail view and the changes propagate correctly to the Primary
View.
我的问题是:如何强制更新 SwiftUI 核心数据中所有相关的 @FetchRequests
?特别是,当我无法直接访问相关实体时/@Fetchrequests
?
My question is:How can I force an update on all related @FetchRequests
in SwiftUI Core Data?Especially, when I have no direct access to the related entities/@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()
}
}
推荐答案
我也为此苦苦挣扎,并找到了一个非常好的和干净的解决方案:
I also struggled with this and found a very nice and clean solution:
您必须将行包装在单独的视图中,并在实体的该行视图中使用 @ObservedObject.
You have to wrap the row in a separate view and use @ObservedObject in that row view on the entity.
这是我的代码:
酒单:
struct WineList: View {
@FetchRequest(entity: Wine.entity(), sortDescriptors: [
NSSortDescriptor(keyPath: Wine.name, ascending: true)
]
) var wines: FetchedResults<Wine>
var body: some View {
List(wines, id: .id) { wine in
NavigationLink(destination: WineDetail(wine: wine)) {
WineRow(wine: wine)
}
}
.navigationBarTitle("Wines")
}
}
WineRow:
struct WineRow: View {
@ObservedObject var wine: Wine // !! @ObserveObject is the key!!!
var body: some View {
HStack {
Text(wine.name ?? "")
Spacer()
}
}
}
这篇关于当 SwiftUI 中的相关实体发生更改时,如何更新 @FetchRequest?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!