在 NSManagedObject 编辑上更新 SwiftUI 视图

Posted

技术标签:

【中文标题】在 NSManagedObject 编辑上更新 SwiftUI 视图【英文标题】:Update SwiftUI View on NSManagedObject edit 【发布时间】:2020-08-07 21:59:30 【问题描述】:

我正在尝试更新有关 NSManagedObject (Training) 的属性更新的 SwiftUI(子)视图。 该属性是一个 NSOrderedSet (exerciceHistories)。

Training 类的片段:

extension Training 

    ...

    @NSManaged public var date: Date
    @NSManaged public var exerciceHistories: NSOrderedSet

主视图是TrainingDetail,显示Training的详细信息:

struct TrainingDetail: View 
    @Environment(\.managedObjectContext) var managedObjectContext
    
    @ObservedObject var training: Training
    ...
    
    var body: some View 
        ZStack 
            ...
            ScrollView(.vertical, showsIndicators: false) 
                VStack(spacing: 0) 
                    ...
                    TrainingDetailAction(training: training, new: new) //-> View that creates sheet to edit one element of training property NSOrderedSet (`exerciceHistories`)
                    TrainingDetailExercices(training: training, editing: $new) //-> View displaying training property NSOrderedSet (`exerciceHistories`)
                        .padding()
                
                ....
            
            ...
        
    

TrainingDetailExercices 的有趣部分,其中打开了编辑表:

struct TrainingDetailExercices: View 
    @Environment(\.managedObjectContext) var managedObjectContext
    
    @ObservedObject var training: Training

    var body: some View 

...

                     ForEach(training.exerciceHistories.array as! [ExerciceHistory], id: \.self) 
                    exerciceHistory in

                     ExerciceHistoryRow(exerciceHistory: exerciceHistory)
                            .padding(.bottom, 10)
                    .sheet(isPresented: $showEditView, onDismiss: 
                    ...
                , content: 
                TrainingAddExercice(training: self.training, ...)
                    .environment(\.managedObjectContext, self.managedObjectContext)
            )

TrainingAddExercice 是显示的工作表,我们可以在其中编辑训练属性 NSOrderedSet (exerciceHistories) 的一个元素:

struct TrainingAddExercice: View 
    ...
    @ObservedObject private var trainingAddExerciceViewModel: TrainingAddExerciceViewModel
    
    @ObservedObject var training: Training
    ...
    

TrainingAddExercice中保存和关闭表单的功能:

    private func trailingNavButtons() -> some View 
            HStack
                ....
                
                Button(action: 
                    self.trainingAddExerciceViewModel.save(exerciceHistory: self.exerciceHistory, to: self.managedObjectContext, for: self.training)
    
    //here I'm trying to force update by creating a new NSMutableOrderedSet and assign it to training (because NSMutableOrderedSet is class, not struct) 

                    let newExercicesHistories = NSMutableOrderedSet(orderedSet: self.training.exerciceHistories)
                    self.training.exerciceHistories = newExercicesHistories
                    self.show = false
              
  , label: 
                ...
            ).disabled(...)
        
    

我不明白的一件事是,当我向 training.exerciceHistories 添加/删除一个 ExerciceHistory 时,查看更新但在我编辑一个时却没有,所以我试图通过创建新的 OrderedSet 来强制.

对象在 CoreData 中得到很好的更新。

【问题讨论】:

你可以使用self.training.objectWillChange.send()强制刷新 ObservableObjects 已经尝试使用self.training.objectWillChange.send() 强制,但不起作用。我在这个问题上挣扎了很多,我很困惑我错过了什么 【参考方案1】:

在花了很长时间试图理解这种行为并使用我对 SwiftUI、CoreData 和 Combine 的所有知识之后,我终于通过将 id 添加到我的 ForEach 来“修复”,如下所示:

ForEach(training.exerciceHistories.array as! [ExerciceHistory], id: \.self) 
exerciceHistory in
    ExerciceHistoryRow(exerciceHistory: exerciceHistory)
    .padding(.bottom, 10)
.id(UUID())

【讨论】:

以上是关于在 NSManagedObject 编辑上更新 SwiftUI 视图的主要内容,如果未能解决你的问题,请参考以下文章

在具有 VIPER 架构的应用程序上更新 NSManagedObject

iOS 8 Swift:使用 segue 编辑 NSManagedObject:声明类型时出错

当模型编辑器中的模型更改时重新创建 NSManagedObject 子类

如何使用更新的数据刷新 NSManagedObject - Core Data

@StateObject 用于没有上下文的 NSManagedObject 不发布更改

在 UITableViewCell 内的 UITextField 中编辑 NSManagedObject