我有一个NSFetchedResultsController,可以查询核心数据实体“MyGalleryPhoto”。
我正在尝试删除一些对象,并遇到一些问题。我正在使用MagicalRecord。这是我对代码的原始尝试,在我看来应该可以正常工作。在运行代码时,对象肯定存在,因为它们显示在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){
}];
此代码不起作用。找不到myGalleryPhoto条目,返回的错误是:“操作无法完成。(Cocoa错误133000.)”我也尝试使用MR_inContext,它只调用existingObjectWithId:error:。
在经历了很多混乱后,我想出了这个卑鄙的frankenstein的怪物,它从实体中获取所有记录并比较ObjectID的字符串表示。这很好用。为什么?我正在使用今天从GitHub下载的MagicalRecord副本,最新的XCode,最新的SDK等等。
[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){
}];
答案 0 :(得分:5)
Cocoa Error 13000是参照完整性错误,如the documentation中所述。这意味着您正在寻找商店中不存在的对象。在更实际的层面上,这意味着您的上下文(我假设您有多个托管对象上下文)不同步。也就是说,您已将一个新对象添加到一个上下文中,而另一个没有该对象,因为之前的上下文尚未保存。
关于你的代码,我在第一个例子中看到的第一个问题是你在一开始就越过了线程边界。 fetchedResultsController具有对另一个上下文中对象的引用(我将假设默认上下文)。每次调用saveInBackground时,它都会为您提供一个新的上下文,但它也会将该代码块放在后台线程上。跨越线程边界,即使在新版本的Core Data中,也会让您疯狂,难以随机追踪问题。
如果您要在第一个(更简单的)代码块中尝试执行的操作,那么您需要从应用程序中删除一组照片对象。我会做这样的事情:
NSPredicate *objectsToDelete = [NSPredicate predicateWithFormat:@"self in %@", self.fetchedResultsController.fetchedObjects];
[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *)localContext
{
[MyGalleryPhoto deleteAllMatchingPredicate:objectsToDelete inContext:localContext];
}];
deleteAllMatchingPredicate方法应该在正确的上下文中查找对象(您在第一个代码块中没有这样做),因此可以删除它们。它还将要加载的对象设置为故障,因此我们不会将所有内容加载到内存中,只是立即将其删除。它只会加载它所需要的东西,而不再加载它。
在这种情况下,我不会使用existingObjectWithID:此方法永远不会加载故障。您的用例意味着它会将整个对象加载到内存中,但无论如何都要删除它。