skip to Main Content

Goal

I want to delete an item from a SectionedFetchRequest on a ForEach inside a List. The only solutions I have found are for a regular FetchRequest I have managed to delete it from the UIList but not from the CoreData’s ViewContext.

My question is unique because I’m trying to delete from a SectionedFetchRequest which is different than a FetchRequest

    @SectionedFetchRequest(entity: Todo.entity(), sectionIdentifier: .dueDateRelative, sortDescriptors: [NSSortDescriptor(keyPath: Todo.dueDate, ascending: true)], predicate: nil, animation: Animation.linear)
    var sections: SectionedFetchResults<String, Todo>
    var body: some View {
        NavigationView {
            List {      
                ForEach(sections) { section in
                    Section(header: Text(section.id.description)) {
                        ForEach(section) { todo in
                            TodoRowView(todo: todo)
                                .frame(maxWidth: .infinity)
                                .listRowSeparator(.hidden)
                        }
                        .onDelete { row in
                            deleteTodo(section: section.id.description, row: row)
                            }
                        }

                    }
                }
    func deleteTodo(section: String, row: IndexSet) {
        // Need to delete from list and CoreData viewContex.
    }
// My old way of deleting notes with a regular fetch Request
func deleteNote(at offsets: IndexSet) {
    for index in offsets {
        let todo = todos[index]
        viewContext.delete(todo)
    }
    try? viewContext.save()
}

2

Answers


  1. This is how you would use the link…

    Add this to the TodoRowView(todo: todo)

    .swipeActions(content: {
        Button(role: .destructive, action: {
            deleteTodo(todo: todo)
        }, label: {
            Image(systemName: "trash")
        })
    })
    

    And you need this method in the View

    public func deleteTodo(todo: Todo){
        viewContext.delete(todo)
        do{
            try viewContext.save()
        } catch{
            print(error)
        }
    }
    

    Or you can use your current setup that uses onDelete on the ForEach

    .onDelete { indexSet in
        deleteTodo(section: Array(section), offsets: indexSet)
        }
    

    That uses this method

    func deleteTodo(section: [Todo], offsets: IndexSet) {
        for index in offsets {
            let todo = section[index]
            viewContext.delete(todo)
        }
        try? viewContext.save()
    }
    

    And of course for any of this to work you need a working

    @Environment(.managedObjectContext) var viewContext
    

    At the top of your file

    Login or Signup to reply.
  2. I found this question when searching for a neat solution, couldn’t find one so thought I’d share my attempt at deleting from a @SectionedFetchRequest.

      var body: some View {
            NavigationView {
                List {      
                    ForEach(sections) { section in
                        Section(section.id) {
                            ForEach(section) { todo in
                                TodoRowView(todo: todo)
                                    .frame(maxWidth: .infinity)
                                    .listRowSeparator(.hidden)
                                    .onDelete { indexSet in
                                        deleteTodos(section: section, offsets: indexSet)
                                    }
                            }
                            
                        }
    
                    }
                }
                ...
    
        private func deleteTodos(section: SectionedFetchResults<String, Todo>.Section, offsets: IndexSet) {
            withAnimation {
                
                offsets.map { section[$0] }.forEach(viewContext.delete)
    
                do {
                    try viewContext.save()
                } catch {
                    // Replace this implementation with code to handle the error appropriately.
                    // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                    let nsError = error as NSError
                    fatalError("Unresolved error (nsError), (nsError.userInfo)")
                }
            }
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search