使用@FetchRequest关联实体的SwiftUI绑定不会更新视图

问题描述

使用SwiftUI,CoreData和@FetchRequest包装器,我只是没有在相关实体的cahnegs上获得任何视图更新。我建立了以下简单而有效的示例:

CoreData模型如下:

GroupEntity -hasMany[items]-> ItemEntity
ItemEntity -hasOne[group]-> GroupEntity

enter image description here

我在CoreData自动生成的类中添加了两个扩展,以绕过这里的讨厌的可选内容底部的按钮创建一个包含三个项目的组。它们的名称相同,但是由于其唯一的ID而确实有所不同。该视图仅在下面列出一个组及其所有相关项及其相应的值。轻按一项将其值增加一。轻触每个组部分底部的“更改 GroupName ”按钮,即可更改该组的名称。除了以下内容外,没有其他代码

import SwiftUI

extension ItemEntity {
    var wName: String { name ?? "nameless item"}
}

extension GroupEntity {
    var wName: String { name ?? "nameless group" }
    var aItems: [ItemEntity] {
        let set = items as? Set<ItemEntity> ?? []
        return set.sorted {
            $0.wName < $1.wName
        }
    }
}

struct ContentView: View {
    @Environment(\.managedobjectContext) var moc
    
    @FetchRequest(entity: GroupEntity.entity(),sortDescriptors: []) var groups: FetchedResults<GroupEntity>
    
    var body: some View {
        List {
            ForEach(groups,id: \.self) { group in
                Section(header: Text("\(group.wName) >> \(group.aItems.reduce(0,{$0 + $1.value}))")) {
                    ForEach(group.aItems,id: \.id) { (item: ItemEntity) in
                        Text("\(item.wName) >> \(item.value)")
                            .onTapGesture {
                                item.value = item.value + 1
                                print("item value: \(item.value)")
                                // -> value changed & stored,but view IS NOT UPDATED
                                try? moc.save()
                            }
                    }
                 
                    Button(action: {
                        group.name = group.wName + " [changed]"
                        // -> value changed,stored and view IS UPDATED
                        try? moc.save()
                    }) {
                        Text("change \(group.wName)")
                    }
                }
            }
            
            Button(action: addGroupItems) {
                Text("Add Group with Items")
            }
        }
    }
    
    func addGroupItems() {
        let group = GroupEntity(context: moc)
        group.id = UUID()
        group.name = "G1"
        
        let item1 = ItemEntity(context: moc)
        item1.id = UUID()
        item1.name = "I1"
        item1.value = 1
        group.addToItems(item1)
        
        let item2 = ItemEntity(context: moc)
        item2.id = UUID()
        item2.name = "I2"
        item2.value = 2
        group.addToItems(item2)
        
        let item3 = ItemEntity(context: moc)
        item3.id = UUID()
        item3.name = "I3"
        item3.value = 3
        group.addToItems(item3)
        
        // save
        try? moc.save()
    }
}

只要更改组名,“视图”就会自动刷新并使更改可见。但是,当点击一个项目时,它的值增加了(如打印语句所示),但视图未更新。请注意额外的要求,即组的节标题包括所有项目值的计算总和。当项目更改时,也应对此进行更新。这就是为什么仅将Item导出到单独的itemRowView(item: item)并将其中的项声明为@Observedobject var item: ItemEntity的原因。

我假设@FetchRequest包装器以某种方式忽略了对相关项目的所有更改。但是我不能相信它对相关数据没有用,因为那是CoreDatas的主要力量?

感谢大家提出任何有用的评论和想法!

解决方法

仅凭想法-尝试以下操作

    .onTapGesture {
        item.value = item.value + 1
        print("item value: \(item.value)")
        // -> value changed & stored,but view IS NOT UPDATED
        try? moc.save()

        group.objectWillChange.send()        // << here !!
    }
,

好的,所以我找到了适合我的解决方案。添加发布者来监视managedObjectContext中的更改,并在发现更改时进行更新即可解决问题。

struct ContentView: View { 
  private var mocDidChanged =  NotificationCenter.default.publisher(for: .NSManagedObjectContextObjectsDidChange)
  /* ... */
  var body: some View {
     List { /* .. */ }.onReceive(self.mocDidChanged) { _ in
        self.refresh()
     }
  }

  func refresh() {
     /* update related state variables here */
  }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...