[英]SwiftUI binding of related entity by using @FetchRequest does not update the view
使用 SwiftUI、CoreData 和 @FetchRequest 包裝器,我根本沒有在相關實體的 cahnegs 上獲得任何視圖更新。 我設置了以下簡單且有效的示例:
CoreData 模型如下所示:
GroupEntity -hasMany[items]-> ItemEntity
ItemEntity -hasOne[group]-> GroupEntity
我向 CoreData 自動生成的類添加了兩個擴展,以避開這里令人討厭的選項。 底部的按鈕創建一個包含三個項目的組。 它們的名稱相同,但由於它們的唯一 ID 而真正不同。 該視圖只是在下面列出了一個組及其所有相關項及其相應的值。 輕敲一件物品會使它的價值增加一。 在各組部分底部攻“更改組名”按鈕更改組的名稱。 除了以下代碼外,沒有其他代碼:
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)
並將 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 */
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.