Issue
Here is the code if you don’t understand
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[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
so the question here is the button there in the forEach loop to delete the item that the user pressed the button and I know how to do it, but what I don’t know is how to get the index of the item and pass it in the function.
Solution
You don’t actually need the index if you’re issuing the delete instruction from within your loop, as your NSManagedObjectContext
instance has a delete(_:)
method that takes the object itself. That change will propagate through your @FetchRequest
object automatically, your SwiftUI view will update to show the collection without the now-deleted object.
So your button action becomes:
Button(action: {
viewContext.delete(prod)
}) {
Image(systemName: ...)
// etc.
}
Note that while you’ll see the effect straight away, the deletion will only be in memory until you call save
on the managed object context.
In my CoreData apps, I tend to save my changes separately, for example when the app is about to go into the background. But if you want to trigger a save immediately the object is removed, that’s straightforward enough:
Button(action: {
viewContext.delete(prod)
try? viewContext.save()
}) {
Image(systemName: ...)
// etc.
}
NB: the documentation for NSManagedObjectContext.save()
says that you should check the hasChanges
property before attempting to save, but as you’ve just made a change in the line above, that’s not necessary in this particular example.
Answered By – Scott Matthewman
Answer Checked By – Terry (BugsFixing Volunteer)