SwiftUI @FetchRequest关系的核心数据更改不会刷新

时间:2019-11-13 21:28:26

标签: swift core-data swiftui combine

一个核心数据模型,其中实体Node具有namecreatedAt,一对多关系children和一对一关系parent(均为可选) 。使用CodeGen类定义。

使用带有谓词{{​​1}}的{​​{1}},可以获取根节点并随后使用关系遍历树。

根节点CRUD可以正常刷新视图,但是对子节点的任何修改直到重新启动后才会显示,尽管更改已保存在核心数据中。

以下代码中最简单的示例说明了删除子节点的问题。删除在Core Data中有效,但是如果删除在子对象上,则视图不会刷新。如果在根节点上,则视图刷新效果很好。

我是Swift的新手,所以我很抱歉,如果这是一个非常基本的问题,但是如何在更改子节点后刷新视图?

@FetchRequest

编辑:

一个简单但不令人满意的解决方案是使parent == nil使用另一个import SwiftUI import CoreData extension Node { class func count() -> Int { let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext let fetchRequest: NSFetchRequest<Node> = Node.fetchRequest() do { let count = try context.count(for: fetchRequest) print("found nodes: \(count)") return count } catch let error as NSError { fatalError("Unresolved error \(error), \(error.userInfo)") } } } struct ContentView: View { @Environment(\.managedObjectContext) var managedObjectContext @FetchRequest(entity: Node.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Node.createdAt, ascending: true)], predicate: NSPredicate(format: "parent == nil")) var nodes: FetchedResults<Node> var body: some View { NavigationView { List { NodeWalkerView(nodes: Array(nodes.map { $0 as Node }) ) } .navigationBarItems(trailing: EditButton()) } .onAppear(perform: { self.loadData() } ) } func loadData() { if Node.count() == 0 { for i in 0...3 { let node = Node(context: self.managedObjectContext) node.name = "Node \(i)" for j in 0...2 { let child = Node(context: self.managedObjectContext) child.name = "Child \(i).\(j)" node.addToChildren(child) for k in 0...2 { let subchild = Node(context: self.managedObjectContext) subchild.name = "Subchild \(i).\(j).\(k)" child.addToChildren(subchild) } } } do { try self.managedObjectContext.save() } catch { print(error) } } } } struct NodeWalkerView: View { @Environment(\.managedObjectContext) var managedObjectContext var nodes: [Node] var body: some View { ForEach( self.nodes, id: \.self ) { node in NodeListWalkerCellView(node: node) } .onDelete { (indexSet) in let nodeToDelete = self.nodes[indexSet.first!] self.managedObjectContext.delete(nodeToDelete) do { try self.managedObjectContext.save() } catch { print(error) } } } } struct NodeListWalkerCellView: View { @ObservedObject var node: Node var body: some View { Section { Text("\(node.name ?? "")") if node.children!.count > 0 { NodeWalkerView(nodes: node.children?.allObjects as! [Node] ) .padding(.leading, 30) } } } } 来检索子级,但是由于该对象已经可用,因此这是错误的。为什么要运行另一个查询?但这也许是目前附加发布功能的唯一方法吗?

我想知道是否还有另一种方式可以直接在孩子中使用NodeListWakerCellView发布者,也许是在@FetchRequest中?

Combine

1 个答案:

答案 0 :(得分:0)

看看ObservedObjectCollection,这在您需要观察相关对象的变化而无需提供观察它们的子视图时很有用。

在我的案例中,激励性示例是一个视图(观察 relation 对象),该视图呈现了从 related 对象衍生的值,而没有观察相关对象本身。