简体   繁体   中英

Core Data cannot delete object that was never inserted error

Disclaimer: I am a total CoreData noob. I am running my app on an iPhone 4S with iOS 6.0.1.

Background

A part of my app acquires images using a UIImagePicker and saves them to disk using CoreData. Said images are associated with Activities in the model. Activities have a one-to-many relationship with Images.

I need to save images to disk immediately after capture and then fault them out of memory, retaining a thumbnail for display. If I do not, iOS will kill my app for using too much memory after a relatively small number of images have been captured.

I made Thumbnails a separate entity to avoid needing to bring the entire image into memory in situations when all I need is the thumbnail. Thumbnails have a one-to-one relationship with Images. Also, for various reasons I am not using Core Data to store the thumbnail image data; instead, I store the filename, and manage the files on disk myself.

All of this means that, should the user cancel adding an Activity after they have already added at least one Image, then both the Images and the Thumbnails that the user added need to be deleted.

Problem

When I try to delete the added image objects, two things happen. First, Core Data complains about my delete rules:

Core Data: annotation: repairing missing delete propagation for to-one relationship image on object <Thumbnail: 0x1dd4d9e0> (entity: Thumbnail; id: 0x1dd4d410 <x-coredata:///Thumbnail/tE7E99D89-C986-4287-ABBD-C6BA7006E9264> ; data: {
    activity = nil;
    fileName = "ECD70C72-745A-4959-BF41-586E9521F1D6";
    image = "0x1dd9f960 <x-coredata:///Image/tE7E99D89-C986-4287-ABBD-C6BA7006E9263>";
}) with bad fault 0x1dd9f960 <x-coredata:///Image/tE7E99D89-C986-4287-ABBD-C6BA7006E9263>

Second, when I try to save the managed object context, the save fails, and Core Data throws an exception. Here's the output from the NSError object:

Error Domain=NSCocoaErrorDomain Code=134030 "The operation couldn’t be completed. (Cocoa error 134030.)"
 UserInfo=0x1f0ca270 {NSAffectedObjectsErrorKey=(
    "<Image: 0x1dd9f910> (entity: Image; id: 0x1dd9f960 <x-coredata:///Image/tE7E99D89-C986-4287-ABBD-C6BA7006E9263> ;
         data: {
             activity = nil;
             image = nil;
             thumbnail = nil;
         })"
), NSUnderlyingException=Cannot delete object that was never inserted.}

SO. Apparently I'm trying to delete an object that I never inserted? Only I'm pretty sure I did.

Relationship Details

Activity <1-*> Image; delete rule: cascade
--> Inverse: Image <1-1> Activity; delete rule: nullify

Image <1-1> Thumbnail; delete rule: cascade
--> Inverse: Thumbnail <1-1> Image; delete rule: nullify

Relevant Code

Image acquisition:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    UIImage* acquiredImage = (UIImage*)info[UIImagePickerControllerEditedImage];
    if (!acquiredImage)  {
        acquiredImage = (UIImage*)info[UIImagePickerControllerOriginalImage];
    }

    // Save the image to disk so we can fault it and free up its memory
    NSManagedObjectContext* moc = [(ATAppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];
    Image* imageToSave = [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:moc];
    Thumbnail* thumbToSave = [NSEntityDescription insertNewObjectForEntityForName:@"Thumbnail" inManagedObjectContext:moc];
    [addedImageManagedObjects addObject:imageToSave];
    [addedThumbnailManagedObjects addObject:thumbToSave];

    [thumbToSave setThumbnailImage:acquiredImage];
    imageToSave.thumbnail = thumbToSave;

    NSError* error;
    [moc save:&error];
    // TODO: error handling

    // I know it doesn't look it, but this call will turn the imageToSave into a fault, thus freeing up its memory
    [moc refreshObject:imageToSave mergeChanges:NO];

    // NOW, we can add the thumbnail image to our collection view
    // NOTE, -thumbnailImage is a method on my Thumbnail NSManagedObject subclass
    [self addImage:[thumbToSave thumbnailImage] toCollectionView:imageDisplayView];

    [self dismissModalViewControllerAnimated:YES];
}

Cancel handler:

- (IBAction)cancel:(id)sender {
    NSManagedObjectContext* moc = [(ATAppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];

    // Delete any images we saved to disk
    // Note that the activity object's changes get discarded b/c they were made on the child managed object context
    // (We couldn't do that for images b/c we needed them to be written to disk and then faulted out of memory)
    for (Thumbnail* thumb in addedThumbnailManagedObjects)  {
        // This method deletes the thumbnail image file whose storage I am managing myself
        [thumb deleteThumbnailFile];
        // I shouldn't have to explicitly delete the thumbnail since the delete of its image should cascade down...right?
    }
    for (Image* image in addedImageManagedObjects)  {
        [moc deleteObject:image];
    }

    NSError* error;
    if (![moc save:&error])  {
        NSLog(@"%@", error);
    }
    // TODO: error handling

    [self resetToPristineState];
    [self.presentingViewController dismissModalViewControllerAnimated:YES];
}

Summary

I can't see where I'm going wrong, and the error messages I'm getting aren't helpful. Worse, googling the error messages isn't giving me any useful results. Hence, I turn to you wonderful experienced people for help.

Oh. Oh man. This mistake is too stupid. I am ashamed.

Okay. Notice how in my image acquisition handler, I never set the image data of the Image managed object? Yeah. Turns out you need to do that. :)

Anyway, I've fixed my own issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM