如何删除 forEach 循环中的一个项目,每个项目都有一个 delete btn。我将 swiftUI 与核心数据一起使用

how to delete an item in a forEach loop with a delete btn for each of it. I use swiftUI with core data

不懂的请看代码

struct cartView: View {
        @Environment(\.managedObjectContext) private var viewContext
    
        @FetchRequest(
            sortDescriptors: [], animation: .default) private var products: FetchedResults<Prod>
        
        let columns = [GridItem(.flexible()), GridItem(.flexible())]
        @State var indx = 0
    
        var body: some View {
            NavigationView {
                ScrollView {
                    VStack {
                        LazyVGrid(columns: columns) {
                            ForEach(products, id: \.self) {prod in
                                let prodItems = Product(name: prod.name ?? "Undefined", price: prod.price ?? "Undefined", type: "type", brand: prod.brand ?? "Undefined", images: [prod.image!,""])
                                
                                    ZStack {
                                    Cells(product: prodItems)
                                    // I want the button below delete the item of the 
                                    // button pressed with the function below
                                    Button(action: {}) {
                                        Image(systemName: "xmark.bin.circle")
                                            .resizable()
                                            .frame(width: 30, height: 30)
                                            .foregroundColor(.red)
                                            .background(.black)
                                            .clipShape(RoundedRectangle(cornerRadius: 20))
                                            .offset(x: 60, y: 45)
                                    }
                                }
                            }
                        }
                    }
                }
                .navigationTitle("Cart")
            }
        }
        
        private func deleteItems(offsets: IndexSet) {
            withAnimation {
                offsets.map { products[[=10=]] }.forEach(viewContext.delete)
    
                do {
                    try viewContext.save()
                } catch {
                    let nsError = error as NSError
                    fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
                }
            }
        }
}

所以这里的问题是 forEach 循环中的按钮删除用户按下按钮的项目,我知道该怎么做,但我不知道如何获取项目并将其传递给函数。

如果您从循环中发出删除指令,您实际上不需要索引,因为您的 NSManagedObjectContext 实例有一个获取对象本身的 delete(_:) 方法。该更改将自动传播到您的 @FetchRequest 对象,您的 SwiftUI 视图将更新以显示没有现在删除的对象的集合。

因此您的按钮操作变为:

Button(action: {
  viewContext.delete(prod)
}) {
  Image(systemName: ...)
  // etc.
}

请注意,虽然您会立即看到效果,但删除只会在内存中,直到您对托管对象上下文调用 save

在我的 CoreData 应用程序中,我倾向于单独保存更改,例如当应用程序即将进入后台时。但是如果你想在对象被移除时立即触发保存,那很简单:

Button(action: {
  viewContext.delete(prod)
  try? viewContext.save()
}) {
  Image(systemName: ...)
  // etc.
}

注意:NSManagedObjectContext.save() 的文档说您应该在尝试保存之前检查 hasChanges 属性,但因为您刚刚进行了更改在上面的行中,在这个特定示例中没有必要。

使用 SwiftUI 删除核心数据项(尤其是在带有 NavigationLinks 的 ForEach 循环中)通常以应用程序崩溃告终。这可以使用特殊修饰符在 IOS 上修复(我将查找),但此时它在 MacOS 上根本不起作用(显然它是一个“系统错误”),并且关闭视图几乎是不可能的,似乎(我已经尝试了很多解决方案——许多适用于 IOS 但不适用于 Mac 应用程序)。 我发现的唯一解决方法是对实体使用 .isFault 操作,并 return 一个空视图。不漂亮但它有效: 使用 SwiftUI 删除核心数据项(尤其是在带有 NavigationLinks 的 ForEach 循环中)通常以应用程序崩溃告终。这可以使用特殊修饰符在 IOS 上修复(我将查找),但此时它在 MacOS 上根本不起作用(显然它是一个“系统错误”),并且忽略视图几乎是不可能的,似乎(我尝试了很多解决方案——许多解决方案适用于 IOS 但不适用于 Mac 应用程序)。

我发现的唯一解决方法是对实体使用 .isFault 操作,return 使用空视图。不漂亮但很管用:

    if entity.isFault {
    EmptyView()
}
else {
    // your regular view body
}