【问题标题】:SwiftUI update view on core data object changeSwiftUI 更新核心数据对象更改视图
【发布时间】:2020-10-29 10:02:57
【问题描述】:

我遇到的问题是,当我从工作表视图更新核心数据资产对象时,更改不会反映在 AssetListView 的 UI 中。 (请注意,从工作表视图插入新对象刷新 AssetListView 的 UI。删除工作表视图中的对象也会刷新 AssetListView 的 UI)唯一不起作用的操作是更新。

当核心数据对象发生变化时,如何让 AssetListView 发生变化?

我有以下 SwiftUI 代码显示来自 CoreData FetchRequest 的资产列表:

struct AssetListView: View {
    @State private var showingSheet = false
    @State private var selectedAssetId: NSManagedObjectID?
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(entity: Asset.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Asset.allocationPercentage, ascending: false)]) var assets: FetchedResults<Asset>
    
    var body: some View {
        VStack {
            Form {
                 ForEach(assets, id: \.self) { asset in
                    Section {
                        AssetRowView(asset: asset)
                            .onTapGesture {
                                self.selectedAssetId = asset.objectID
                                self.showingSheet = true
                        }
                    }
                }
            }
            
        }
        .navigationBarTitle("Assets").sheet(isPresented: $showingSheet ) {
                EditAssetView(assetId: self.selectedAssetId!)
                    .environment(\.managedObjectContext, self.moc)
                }
        }
     }
}

这是一个编辑屏幕,我将其呈现为 SwiftUI 工作表:

struct EditAssetView: View {
    var assetId: NSManagedObjectID
    @Environment(\.presentationMode) var presentationMode
    @State private var name = ""
    @State private var description = ""
    @Environment(\.managedObjectContext) var moc
    
    var asset: Asset {
        moc.object(with: assetId) as! Asset
    }
   
    var body: some View {
        NavigationView {
            Form {
                Section {
                    TextField("Name", text: $name)
                    TextField("Description", text: $description)
                }
            }
            .navigationBarTitle(Text("Edit Asset"), displayMode: .inline)
            .navigationBarItems(leading: Button("Cancel") {
                self.presentationMode.wrappedValue.dismiss()
                }, trailing: Button("Done") {
                    self.presentationMode.wrappedValue.dismiss()
                    self.asset.name = self.name
                    self.asset.assetDescription = self.description
                    try? self.moc.save()
                }
            )
        }
        .onAppear {
            self.name = self.asset.name
            self.description = self.asset.assetDescription
        }
    }
}

这是 AssetRowView 的代码:

struct AssetRowView: View {
    var asset: Asset?
    
    var body: some View {
        HStack {
           Text(asset.name)
           Text(asset.assetDescription)
        }
    }
}

【问题讨论】:

    标签: ios swift core-data swiftui


    【解决方案1】:

    尝试观察Asset(因为NSManagedObject is-a ObservableObject

    struct AssetRowView: View {
        @ObservedObject var asset: Asset        // << here !!
        
        var body: some View {
            HStack {
               Text(asset.name)
               Text(asset.assetDescription)
            }
        }
    }
    

    如果这还不够,还可能需要将Done 按钮操作更新为

    }, trailing: Button("Done") {
        self.asset.objectWillChange.send()             // << here !!
        self.asset.name = self.name
        self.asset.assetDescription = self.description
        try? self.moc.save()
    
        // better do this at the end of activity
        self.presentationMode.wrappedValue.dismiss()
    }
    

    【讨论】:

    • 谢谢!只是让它 ObservedObject 工作。不需要调用 objectWillChange.send()
    • 如果UI元素来自关系,如何更新?例如,class > student,一个班级有一些学生。在班级列表视图中,每个班级单元格都显示班级名称和学生人数。当点击班级单元格时,可以编辑班级和添加/删除学生。学生更改后,如何更新班级单元格?
    【解决方案2】:

    我所做的是将核心数据对象传递为:

    @ObservedObject var toDo: FetchedResults<ToDoModelCoreData>.Element
    

    来自我的抓取结果

    @FetchRequest var todoFetchRequest: FetchedResults<ToDoModelCoreData>
    

    这将确保 swiftUI 视图在 coredata 更新时更新

    【讨论】:

      【解决方案3】:

      @ObservedObject 添加到核心数据对象是可行的,但您可能需要滚动列表才能看到更改。取决于您如何设置谓词、托管对象和获取请求。

      在任何编辑 NSManagedObject 的进程结束时添加 foo.objectWillChange.send() 可以解决此问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-09
        • 1970-01-01
        • 1970-01-01
        • 2020-06-30
        • 1970-01-01
        • 2020-11-15
        相关资源
        最近更新 更多