簡體   English   中英

通過使用@FetchRequest 關聯實體的 SwiftUI 綁定不會更新視圖

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM