2

Getting EXC_BAD_ACCESS when deleting objects from Core Data. Any ideas how to solve the problem? May need some read up on Core Data principles (?)

func deleteEntity(_ entity : String) {

        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity)

        print("Object count:  \(context.registeredObjects.count)") // prints 0 here
        do {
            let results = try context.fetch(fetchRequest)
            for managedObject in results {
                let managedObjectData : NSManagedObject = managedObject as! NSManagedObject
                if !managedObjectData.isDeleted{
                    context.delete(managedObjectData)  // EXC_BAD_ACCESS here, fetch request returns 1 item here!
                }
            }
            try context.save()
        } catch let error {
            print(error)
        }
    }




Crashed: com.apple.main-thread
0  CoreData                       0x1114c7293 -[NSManagedObjectContext(_NSInternalAdditions) _registerObject:withID:] + 35
1  CoreData                       0x1114c5569 -[NSManagedObjectContext(_NSInternalAdditions) _retainedObjectWithID:optionalHandler:withInlineStorage:] + 217
2  CoreData                       0x1114d0512 _PF_FulfillDeferredFault + 882
3  CoreData                       0x1114dfe9e _PF_Handler_Primitive_GetProperty + 110
4  CoreData                       0x1114dfca3 -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:] + 323
5  CoreData                       0x1114dfb39 -[NSManagedObject(_NSInternalMethods) _newAllPropertiesWithRelationshipFaultsIntact__] + 89
6  CoreData                       0x1114dfa2b -[NSManagedObjectContext(_NSInternalChangeProcessing) _establishEventSnapshotsForObject:] + 75
7  CoreData                       0x1114f7168 -[NSManagedObjectContext deleteObject:] + 136

Edit: Seems to be something wrong with the context. I've also tried to remove the entire store, but one item seems to remain, causing the crash. This specific item is added later, in a different view. Maybe it has to do with relationships. Debugging with -com.apple.CoreData.ConcurrencyDebug 1 stack trace also shows

"An NSManagedObject may only be in (or observed by) a single NSManagedObjectContext."

Dan
  • 173
  • 2
  • 18
  • It appears that the intent of the function in your code is to delete all objects of a given entity. Is that indeed your intention? – Jerry Krinock Nov 01 '18 at 15:44
  • Yes, all objects should be removed. Have also tried to remove the persistent store files before (including `context.reset` _and_ after this function. – Dan Nov 01 '18 at 23:29
  • Did you find a solution for it? I'm having a similar crash and almost identical stack trace when trying to set a value to a property of a MO. I'm not able to reproduce it though, it is just happening for 2 different users. – Gabriel Gava Mar 21 '19 at 21:13
  • @Gabriel Gava: I didn't manage to find out what actually caused the crash, but I don't have this specific problem anymore. I had removed a "savePrivateContext()" call after inserting data which may have had something to do with it. I also have three different contexts and learned that it's extremely important that you are referencing the correct context when working with Core Data... – Dan Mar 22 '19 at 09:49

2 Answers2

1

The ususal way to delete all objects of an entity is

func deleteEntity(_ entity : String) throws {
    let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: entity)
    let results = try context.fetch(fetchRequest)
    for managedObject in results {
       context.delete(managedObject) 
    }

    try context.save()
}

However in iOS 9+, macOS 10.11+ there is a better way

func deleteEntity(_ entity : String) throws {
    let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: entity)
    let deleteRequest = NSBatchDeleteRequest(fetchRequest: request as! NSFetchRequest<NSFetchRequestResult>)
    let persistentStoreCoordinator = context.persistentStoreCoordinator!
    try persistentStoreCoordinator.execute(deleteRequest, with: context)

    try context.save()
}
vadian
  • 274,689
  • 30
  • 353
  • 361
  • Tried the latter one as well, batch delete, but it doesn't work at all in my case. The items would remain in the store, even though `self.context.registeredObjects.count` returns 0 – Dan Nov 02 '18 at 11:24
  • 1
    `registeredObjects` is irrelevant. Check that the `save` line runs on the same thread as the context. – vadian Nov 02 '18 at 11:59
0

I see several issues with your code…

  • NSManagedObjectContext.registeredObjects.count will count all objects in the context, of all entities. This is probably not what you want (unless there is only one entity in your data model).
  • I don't see any exit from the do{...}.
  • managedObjectData appears to be the same as managedObject, except declared as being not nil, when in fact it may be nil. (This is probably what is causing the crash.)
  • You should call context.save() only once, after the loop exits.

But you should not use that code anyhow. Instead, replace it with one of the better ways to delete all objects of a given entity, as given in answers to this question.

Jerry Krinock
  • 4,860
  • 33
  • 39