从 SwiftUI 列表中删除包含分区的 CoreData

Deleting CoreData from SwiftUI List with Sections

提问人:Justin Comstock 提问时间:12/18/2021 最后编辑:Justin Comstock 更新时间:3/3/2023 访问量:1839

问:

目标

我想从列表中删除一个项目。我找到的唯一解决方案是对于常规,我已经设法从 UIList 中删除了它,但没有从 CoreData 的 .SectionedFetchRequestForEachFetchRequestViewContext

我的问题是独一无二的,因为我正在尝试从与 FetchRequest 不同的 SectionedFetchRequest 中删除

    @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()
}
iOS Swift iPhone Core-数据 SwiftUI

评论

0赞 lorem ipsum 12/18/2021
这回答了你的问题吗?从 CoreData 中删除数据
0赞 Justin Comstock 12/18/2021
@loremipsum嗯,我不确定在我的上下文中如何利用该答案,因为我使用的是 ForEach 循环。我还没有看到 sectionedFetchRequest 的删除解决方案。
0赞 lorem ipsum 12/18/2021
这个答案是你可以用这种方法使用的最实用的答案。您仍然可以按原样使用 indexSet,但您必须对本节中的数组执行此操作。它不适用于所有对象。swipeActions
0赞 Justin Comstock 12/18/2021
@loremipsum尝试过该解决方案,但是我会在.onDelete的上下文中放入什么?我不知道要将什么传递到该函数或访问待办事项。

答:

17赞 lorem ipsum 12/18/2021 #1

这是您使用链接的方式...

将此添加到TodoRowView(todo: todo)

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

你需要这个方法在View

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

或者,您可以使用当前设置,该设置在onDeleteForEach

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

使用此方法

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

当然,要使这些工作起作用,您需要一个工作

@Environment(\.managedObjectContext) var viewContext

在文件顶部

评论

1赞 Justin Comstock 12/18/2021
成功了!再次感谢。整个数组和 IndexSet 部分仍然令人困惑,我想我需要弄清楚更多。
1赞 lorem ipsum 12/18/2021
@JustinComstock 提供用户已选择删除的索引项 () 集。滑动时,它只有一个,但如果你把一个编辑按钮放在上面,你可以删除多个项目(这就是为什么你需要循环)。每个都有自己的 /array 项目,因此需要传递数组以删除它,因为您必须搜索特定部分。onDeleteindexSetListsectionForEachtodo
0赞 abegehr 3/17/2023
在删除节中的最后一项时,我收到“NSInternalInconsistencyException”,原因:“尝试从更新前仅包含 1 项的第 0 节中删除第 1 项”,使用 swipeActions 解决方案。不知道是什么原因。🤔
1赞 lorem ipsum 3/19/2023
@abegehr不知道,我知道这在早期版本的 SwiftUI 和旧版本的 Xcode 中很常见。如果没有最小可重现示例,就不可能帮助您进行故障排除。您可以将其包含在某人会帮助您的问题中。
1赞 malhal 2/6/2023 #2

我在寻找一个简洁的解决方案时发现了这个问题,找不到一个,所以我想我会分享我从中删除的尝试。@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)")
            }
        }
    }

评论

0赞 FrugalResolution 3/3/2023
非常整洁!我喜欢它与原来的相似。