Search code examples
swiftmacoscore-dataswiftuiswiftui-alert

Swift - Thread 1: EXC_BAD_INSTRUCTION when deleting object from Coredata


I'm trying to delete an object from Coredata, and I sometimes get the error Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0), and my app crashes, when I delete an object. The console also spits out tons of information but this seem like the most important thing:

[General] *** __boundsFail: index 2 beyond bounds [0 .. 1]

The strange thing is that this only happens when I call the function to delete the object from an Alert.

This is the function that deletes the object:

    private func deleteInstances(offsets: IndexSet) {
        if instances.count == 1 {
            showingCantDeleteInstanceAlert = true
            return
        }
        
        for index in offsets {
            let instance = instances[index]
            print(instance)
            viewContext.delete(instance)
        }
        
        do {
            try viewContext.save()
        } catch {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }

        if selectedInstanceIndex ?? 0 >= instances.count {
            selectedInstanceIndex = instances.count - 1
        }
        
    }

And I'm using a focusedValue to call that function from a menu command:

.focusedValue(\.deleteInstanceAction) {
    deleteInstances(offsets: [selectedInstanceIndex ?? 0])//selectedInstanceIndex is the index of the object that is selected in a navigationView and therefore the object I want to delete
}

This always works fine, but I want this to display an alert which makes sure the user actually wants to delete the instance:

.focusedValue(\.deleteInstanceAction) {
    showingConfirmDeleteInstanceAlert = true

And the alert:

.alert(isPresented: $showingConfirmDeleteInstanceAlert) {
    Alert(
        title: Text("Are you sure you want to delete instance \"\(instances[selectedInstanceIndex ?? 0].wrappedName)\"?"),
        message: Text("This action cannot be undone."),
        primaryButton: .cancel(),
        secondaryButton: .destructive(Text("Delete")) {
            deleteInstances(offsets: [selectedInstanceIndex ?? 0])
        }
    )
}

However, when the function is run from here instead, I sometimes get that error. It only happens when I try to delete the last instance in the navigationView.

I am at a loss as to what might be happening, as far as I can tell the same code should be run either way, but in the version with the alert it doesn't always work.

Any help figuring out what's happening would be greatly appreciated. Thanks!


Solution

  • Try using the instance's managedObjectContext, so something like:

    let context = instance.managedObjectContext
    context.delete(instance)
    
    do {
        try context.save()
    } catch {
        let nsError = error as NSError
        fatalError("Unresolved error \(nsError),  \(nsError.userInfo)")
    }
    

    if that doesn't work, try pushing your call to the function to the main thread, this isn't the best, but you are using viewContext so you have to be on the "UI Thread" or the main thread. so something like:

    DispatchQueue.main.async {
        deleteInstances(offsets: [selectedInstanceIndex ?? 0])
    }