Jopolaz
Jopolaz

Reputation: 412

Update SwiftUI View on NSManagedObject edit

I'm trying to update a SwiftUI (sub) view on property update of NSManagedObject (Training). The property is an NSOrderedSet (exerciceHistories).

Piece of Training class :

extension Training {

    ...

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

The main view is TrainingDetail, displaying detail of 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()
                }}
                ....
            }
            ...
        }
    }

Interesting part of TrainingDetailExercices, where editing sheet is opened :

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 that is the sheet displayed, where we can edit one element of training property NSOrderedSet (exerciceHistories):

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

The function that save and close sheet in 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(...)
        }
    }

One thing I don't understand is that when I'm adding/deleting one ExerciceHistory to/of training.exerciceHistories, view updates but not when I'm editing one even so I'm trying to force by creating new OrderedSet.

Object is well update in CoreData.

Upvotes: 0

Views: 170

Answers (1)

Jopolaz
Jopolaz

Reputation: 412

After spending a long time trying to understand the behavior and using all my knowledge of SwiftUI, CoreData and Combine, I finally "fix" by adding id to my ForEach like this :

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

Upvotes: 0

Related Questions