24

I have two entities, each displaying on its own UITableView section.

I've enabled editing to allow the user to delete rows by swiping to the right. This works fine for the first entity, but when I try to delete an object in the second entity, I get this error:

An NSManagedObjectContext cannot delete objects in other contexts

I get what the error says, but I can't see how it applies here. I use a retained reference to my context to create, fetch, and delete all objects from the database, so I'm sure there's only the one context. I'm also not using multiple threads. Any idea what could be happening?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
cetcet
  • 2,147
  • 2
  • 15
  • 15

5 Answers5

25

Is the context that you fetched the NSManagedObject from, the same instance, as the context you're using to delete the NSManagedObject? If not, you need to either:

  • Have a shared reference to the same NSManagedObjectContext so that you delete the object from the same context that you created or fetched it from. If you're not using multiple threads, then you should only need to call [[NSManagedObjectContext alloc] init] once ever in your code.

or

  • If you have to use two different instances of NSManagedObjectContext, then get the objectID from the NSManagedObject you got from the first context, so that you can later call:

    [context deleteObject:[context objectWithID:aObjectID]];
    

    The NSManagedObjectID is the same between contexts, but the NSManagedObject itself is not.

GoGreen
  • 2,251
  • 1
  • 17
  • 29
dominostars
  • 293
  • 2
  • 5
  • I'm using the managedObjectContext ivar in the app delegate (put there by xcode when I created the project). The code that's causing the error references uses [[[UIApplication sharedApplication] delegate] managedObjectContext]. There's only that one instance used throughout the app. – cetcet May 03 '11 at 05:44
  • Just fixed it. It was a typo - nothing to do with the context. Sorry, and thanks for the help! – cetcet May 03 '11 at 06:07
  • 14
    For anyone else coming across this in a Google search, you MAY receive this error if you are passing an invalid object or other mistyped code to `[managedObjectContext deleteObject];` I was passing an `NSNumber*` on accident and it was giving me this error instead of telling me I should be passing an `NSManagedObject*`. – Riley Dutton Oct 25 '11 at 10:36
  • 3
    Just to add to @RileyDutton answer - You can't delete an object if you fetched only his managed object id (via `...setResultType:NSManagedObjectIDType]` for `NSFetchRequest`. – Eimantas Aug 08 '12 at 08:22
  • @RileyDutton Yes you are absolutely right even I had also mistakenly passed the wrong object and getting the same error again and again but As a I saw your explanation got the actual reason Thanks !!! – Kamar Shad Apr 26 '16 at 11:31
7

I use this:

  func delete(object: YourManagedObject) {
    guard let context = object.managedObjectContext else { return }

    if context == self.viewContext {
      context.delete(object)
    } else {
      self.performBackgroundTask { context in
      context.delete(object)
    }
  }

  try? self.viewContext.save()
}

Basically, it is quite likely that the object that you want to delete was provided by the viewContext of NSPersistentContainer. So trying to delete from the private background context won't work.

Andrew Eades
  • 127
  • 1
  • 6
1

I'm not sure if it answers your question, but I had similar crash when I tried to delete CoreData object in Swift. I fixed it calling objectId

func deleteNumber(phoneNumber: PhoneNumber) {
    let objectToDelete = container.viewContext.object(with: phoneNumber.objectID)
    container.viewContext.delete(objectToDelete)

//save context
    if container.viewContext.hasChanges {
        do {
            try container.viewContext.save()
        } catch {
            print("An error occurred while saving: \(error)")
        }
    }
}
Alex Metelkin
  • 1,520
  • 7
  • 13
0

This answer expounds on the case described in the comments by Riley Dutton about the error message being misleading.

The error message will display when you pass an object which is not a subclass of NSManagedObject to deleteObject:. Riley hit the problem simply by passing in the wrong object explicitly, but I got there by Core Data changes.

My project deployment target was set to 7.0, and this code worked without errors even running on iOS 9.3:

NSArray *entries = @[self.colorList.colors, self.emotionList.emotions, self.shapeList.shapes];
    for (id entry in entries) {
        [[self managedObjectContext] deleteObject:entry];
    }

When I updated the project deployment target to 9.3, I started getting the error message.

Here is the description of entry:

Relationship 'colors' fault on managed object (0x7fd063420310) <MyColorList: 0x7fd063420310> (entity: MyColorList; id: 0xd000000000640006 <x-coredata://12556DEF-F77E-4EFF-AAE6-55E71A3F5420/MyColorList/p25> ; data: {
    attachedThing = "0xd0000000000c0004 <x-coredata://12556DEF-F77E-4EFF-AAE6-55E71A3F5420/MyThing/p3>";
    colors = "<relationship fault: 0x7fd063468f30 'colors'>";
})

It looks like Apple changed the rules for when Core Data will trigger a fault and actually pull the data from the persistent store coordinator.

This modification solved the problem:

NSArray *entries = @[self.colorList.colors, self.emotionList.emotions, self.shapeList.shapes];
    for (id entry in entries) {
        for (id e in entry) {
            [[self managedObjectContext] deleteObject:e];
        }
    }

At this time I do not know if this is the ideal way to solve this problem or if there is a more canonical way to tell Core Data to trigger the fault and read the data from disk.

Jeff
  • 3,829
  • 1
  • 31
  • 49
0

Complementing the answer given by dominostars, when using SwiftUI, just declare a reference to the managed object context once like @Environment(\.managedObjectContext) var moc and then pass this reference to every other view that requires access. Do not declare the reference twice.