Updating previous view list when deleting an object

Viewed 357

I have two views, one is presenting a list of objects and the second present detail on each object. The second view have the option to delete an object. The set of objects is observed and stored in the Data Base using Core Data.

When deleting an object on the second view and forcing return to the first view (using: self.mode.wrappedValue.dismiss() ), the object name stays on the list. Maybe I am wrong but I think that this is not a binding problem but the fact that the view isn't iterating on the set again.

How should I reload the list when returning back ?

This is the list view:

 struct AssignmentList: View {

    @ObservedObject var assignmentViewModel = AssignmentViewModel()

    var body: some View {

        NavigationView {
            VStack{
                List(Array(assignmentViewModel.allAssignments), id: \.self) { assignment in
                    NavigationLink(destination: DetailedAssignment(assignmentName:assignment.assignmentName as! String,notes: assignment.notes as! String)){
                            AssignmentRow(assignmentName: assignment.assignmentName as! String)
                            }
                             
                         }
                      .navigationBarTitle(Text("Assignments"))
                        
                        Button(action: {
                                       
                            self.assignmentViewModel.retrieveAllAssignments()
                                                
                                                                 
                                }) {
                                        Text("Retrieve")
                                    }
                       
                        }
             }
            
         
}
}

The delete button in the second view :

struct DetailedAssignment: View {
    
    @Environment(\.presentationMode) var mode: Binding<PresentationMode>
    
    @ObservedObject var assignmentViewModel = AssignmentViewModel()

    var assignmentName : String
    var notes :String

    
    var body: some View {

          Button(action: {
                             
            self.assignmentViewModel.deleteAssignment(assignmentName: self.assignmentName as! String)
            self.assignmentViewModel.retrieveAllAssignments()//In order to update the observed object set
                
            self.mode.wrappedValue.dismiss()
         
                                                       
                                                      }) {
                                                                  
                                                          Text("Delete")
                                                      }
            
         }
    }
}

Relevant part from AssignmentViewModel:

class AssignmentViewModel : ObservableObject
{
  @Published var allAssignments : Set<Assignment>

}

Delete func from the Model:

func deleteAssignment(assignmentName : String){
    
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }


let managedContext = appDelegate.persistentContainer.viewContext

let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Assignment")
fetchRequest.predicate = NSPredicate(format: "assignmentName = %@", assignmentName)

do
{
    let requiredAssignment = try managedContext.fetch(fetchRequest)
    
    let objectToDelete = requiredAssignment[0] as! NSManagedObject
    managedContext.delete(objectToDelete)
    
    do{
        try managedContext.save()
        print("Deleted !.")
    }
    catch
    {
        print(error)
    }
    
}
catch
{
    print(error)
}

}

1 Answers

I reproduced that code and I was really wondering why it wasn't working. But then I found the error. You are creating another new Observable Object in the Detail View. That is wrong, because you are referencing another object and not the first in your List View. You only create the Object once and pass it to the subview.

In your Detail View change it to this:

struct DetailedAssignment: View {
    
    @Environment(\.presentationMode) var mode: Binding<PresentationMode>
    
    @ObservedObject var assignmentViewModel : AssignmentViewModel

Than pass it from your List View like that:

NavigationLink(destination: DetailedAssignment(assignmentViewModel: assignmentViewModel, self. assignmentName:assignment.assignmentName as! String,notes: assignment.notes as! String)){
                            AssignmentRow(assignmentName: assignment.assignmentName as! String)
                            }

Make sure Assignment conforms to Identifiable, Equatable, Hashable. I actually recreated it with Array, however Set should work aswell.

Edit:

As you now shown that you work with CoreData, I think the best way would be to use @FetchRequest inside your ListView. You won't need a Observable object, as FetchRequest will do the same you are currently doing manually.

You have to call ...

self.assignmentViewModel.retrieveAllAssignments()//In order to update the observed object set

.. in your delete function.

Related