MagicalRecord + Core Data cannot find objects between contexts, even though

I have an NSFetchedResultsController that requests a Core Data object, MyGalleryPhoto.

I am trying to delete some objects and solve some problems. I am using MagicalRecord. Here is my original code attempt, which, in my opinion, should work fine. At the point at which code is executed, objects definitely exist because they are displayed in the fetchedResultsController.

[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { for (MyGalleryPhoto *myGalleryPhoto in [self.fetchedResultsController.fetchedObjects objectsAtIndexes: self.selectedIndexes]) { NSError *error = nil; MyGalleryPhoto *localMyGalleryPhoto = (MyGalleryPhoto *) [localContext existingObjectWithID: myGalleryPhoto.objectID error: &error]; NSLog(@"error: %@:%@", [error localizedDescription], [error userInfo]); NSLog(@"mygp: %@", [localMyGalleryPhoto description]); [localMyGalleryPhoto deleteInContext: localContext]; } } completion:^(void){ }]; 

This code does not work. MyGalleryPhoto entry was not found and the error received was: "Operation could not be completed. (Cocoa error 133000.)" I also tried using MR_inContext, which simply calls existingObjectWithId: error :.

After many turmoil, I came up with this vile Frankenstein monster that extracts all records from an entity and compares ObjectID string representations. It works great. What for? I am using a copy of MagicalRecord, which I downloaded from GitHub today, updated Xcode, the latest SDK, etc.

 [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { NSArray *allMyGalleryPhotos = [MyGalleryPhoto findAllInContext: localContext]; for (MyGalleryPhoto *myGalleryPhoto in [self.fetchedResultsController.fetchedObjects objectsAtIndexes: self.selectedIndexes]) { MyGalleryPhoto *myGalleryPhotoToDelete = nil; for (MyGalleryPhoto *existingMyGalleryPhoto in allMyGalleryPhotos) { NSString *existingURLString = [[existingMyGalleryPhoto.objectID URIRepresentation] absoluteString]; NSString *URLString = [[myGalleryPhoto.objectID URIRepresentation] absoluteString]; NSLog(@"ExistingURLString: %@", existingURLString); NSLog(@"URLString: %@", URLString); if ([URLString isEqualToString: existingURLString]) { myGalleryPhotoToDelete = existingMyGalleryPhoto; } } if (myGalleryPhotoToDelete) [myGalleryPhotoToDelete deleteInContext: localContext]; } } completion:^(void){ }]; 
+4
source share
1 answer

Cocoa Error 13000 is a referential integrity error, as described in the documentation . This means that you are looking for an object that does not exist in the store. At a more practical level, this means that your contexts (I assume you have more than one managed entity context) are not in sync. That is, you added a new object in one context, while the other does not have this object, because the previous context was not saved.

As for your code, the first problem that I see in the first example is that you cross thread boundaries from the start. The fetchedResultsController has a reference to objects in a different context (I'm going to accept the default context). Each time saveInBackground is called, it gives you a new context to use, but also places this block of code in the background thread. Crossing the boundaries of threads, even in the new version of Core Data, will lead you to crazy, it is difficult to track problems at random.

If you are trying to make the first (simpler) block of code, you have a collection of photo objects that you want to remove from your application. I would do something like this:

 NSPredicate *objectsToDelete = [NSPredicate predicateWithFormat:@"self in %@", self.fetchedResultsController.fetchedObjects]; [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *)localContext { [MyGalleryPhoto deleteAllMatchingPredicate:objectsToDelete inContext:localContext]; }]; 

The deleteAllMatchingPredicate method must search for objects in the correct context (which you did not do in the first block of code) so that they can be deleted. It also sets objects to load as errors, so we will not load everything in memory, but only to delete them immediately. He will download only what he needs, and no more.

I would not use existingObjectWithID: in this case. This method never loads errors. Your use case means that it will load the entire object into memory, but will delete it anyway.

+5
source

All Articles