Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CoreData: "Cannot delete object that was never inserted."

For the life of me I can't work this one out, but CoreData keeps throwing me an error.

Cannot delete object that was never inserted.

Here is the jist of my app cycle:

1/ Push ViewController.

2/ Get managed object context from app delegate.

FLAppDelegate *appDelegate = (FLAppDelegate *)[[UIApplication sharedApplication] delegate];
    self.managedObjectContext = appDelegate.managedObjectContext;

3/ Check if Session exists.

4/ No Session exists, create a new one.

    self.session = nil;
            self.session = [NSEntityDescription insertNewObjectForEntityForName:@"Session" inManagedObjectContext:self.managedObjectContext];

    //Set attributes etc...

//Keep a reference to this session for later
    [[NSUserDefaults standardUserDefaults] setURL:self.session.objectID.URIRepresentation forKey:kKeyStoredSessionObjectIdUriRep];
            [[NSUserDefaults standardUserDefaults] synchronize];

            NSError *error = nil;
            if (![self.managedObjectContext save:&error])
            {
                //Handle error if save fails
            }

5/ Pop ViewController.

6/ Return to ViewController.

7/ Again, check if Session exists.

8/ A Session is found! (By looking at NSUserDefaults for the one we stored to later reference). So I get Session I created earlier then give the user a choice to delete that one and start fresh or continue with that one.

NSURL *url = [[NSUserDefaults standardUserDefaults] URLForKey:kKeyStoredSessionObjectIdUriRep];
    if (url) //Found existing flight session
    {
        NSManagedObjectID *objId = [self.managedObjectContext.persistentStoreCoordinator managedObjectIDForURIRepresentation:url];
        NSManagedObject *obj = [self.managedObjectContext objectWithID:objId];
        self.session = (Session *)obj;

        //Ask the user if they want to continue with this session or discard and start a new one
    }

9/ Choose to delete this Session and start a new one.

10/ Problem begins here! I delete the reference I am keeping to this Session as it is no longer relevant and try to delete the object then save those changes.

[[NSUserDefaults standardUserDefaults] removeObjectForKey:kKeyStoredSessionObjectIdUriRep];
            [[NSUserDefaults standardUserDefaults] synchronize];

            [self.managedObjectContext deleteObject:self.session];
            NSError *error = nil;
            if (![self.managedObjectContext save:&error])
            {
                //Error!
            }

11/ There we have it, when I try to run the save method, it crashes and throws an error: NSUnderlyingException = "Cannot delete object that was never inserted.";

I have no clue why it says so, as I appear to save the object whenever I create one and create the reference, retrieve the object from that reference but then deleting just breaks everything.

like image 638
Josh Kahane Avatar asked Nov 24 '13 16:11

Josh Kahane


People also ask

How do I delete an object in core data?

Table views have a built-in swipe to delete mechanic that we can draw upon to let users delete commits in our app. Helpfully, managed object context has a matching delete() method that will delete any object regardless of its type or location in the object graph.

Is NSManagedObjectContext thread safe?

The NSManagedObjectContext class isn't thread safe. Plain and simple. You should never share managed object contexts between threads. This is a hard rule you shouldn't break.

What is NSManagedObjectContext in core data?

An object space to manipulate and track changes to managed objects.


1 Answers

The problem is in your step 4. In this step you

  1. Create the Session
  2. Save its managed object ID to user defaults
  3. Save changes to your managed object context.

The reason this fails is that when you create a new managed object, it has a temporary object ID that is only valid until you save changes. As soon as you save changes, it gets a new, permanent object ID. You're saving the temporary object ID, but when you look it up later it's not valid any more.

You can fix this just by changing the order of operations in step 4 so that you:

  1. Create the Session
  2. Save changes to your managed object context
  3. Save the Session's object ID to user defaults

This way you'll have a permanent ID when you save the value to user defaults.

like image 57
Tom Harrington Avatar answered Sep 25 '22 14:09

Tom Harrington