gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 09:25:58 25 4
gpt4 key购买 nike

带有实体 Node 的核心数据模型有 name , createdAt , 多对多关系 children和一对一的关系parent (都是可选的)。使用 CodeGen 类定义。

使用 @FetchRequest谓词为 parent == nil ,可以获取根节点并随后使用关系遍历树。

根节点 CRUD 可以很好地刷新 View ,但对子节点的任何修改在重新启动之前都不会显示,尽管更改已保存在 Core Data 中。

下面代码中最简单的示例说明了子节点删除的问题。删除在 Core Data 中有效,但如果删除是在子级上,则 View 不会刷新。如果在根节点上, View 刷新工作正常。

我是 Swift 的新手,所以如果这是一个相当基本的问题,我很抱歉,但是如何在更改子节点时刷新 View ?

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 检索 child 但这感觉不对,因为该对象已经可用。为什么要运行另一个查询?但也许这是目前附加发布功能的唯一方法?

我想知道是否还有其他方法可以使用 Combine出版商直接给 children ,也许在 .map内?
struct NodeListWalkerCellView: View {

@ObservedObject var node: Node

@FetchRequest var children: FetchedResults<Node>

init( node: Node ) {
self.node = node
self._children = FetchRequest(
entity: Node.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \Node.createdAt, ascending: false)],
predicate: NSPredicate(format: "%K == %@", #keyPath(Node.parent), node)
)
}

var body: some View {

Section {
Text("\(node.name ?? "")")
if node.children!.count > 0 {

NodeWalkerView(nodes: children.map({ $0 as Node }) )

.padding(.leading, 30)
}
}
}
}

最佳答案

看看ObservedObjectCollection ,如果您需要观察相关对象的变化而不显示观察它们的 subview ,这很有用。
在我的例子中的激励示例是一个 View (观察相关对象),它呈现了从相关对象派生的值,而不观察相关对象本身。

关于SwiftUI @FetchRequest 对关系的核心数据更改不刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58845896/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com