如何删除 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
}
不懂的请看代码
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
}