对于在主线程的appDelegate managedObjectContext中创build的对象,“核心数据无法完成错误”

我错误地在后台线程上创build了一组对象,它创build了一个新的managedObjectContext,其中保存了对象。

这导致了许多“核心数据无法完成的错误”在我的现场应用程序崩溃。 请注意 – 我不是试图删除这些对象 – 这是一个问题,他们的创build方式,当我尝试在主线程上的应用程序委托(主)上下文中再次保存它们。

令人困惑的是我看到这个错误的其他对象,不同types的对象。 它们可以与在后台线程中创build的对象相关,尽pipe它们本身并不是在后台线程中创build的。

我很困惑这是怎么发生的。 我怎么能得到“核心数据不能履行过错”错误的对象不是在后台线程中创build,但应用程序委托(主)上下文?

有没有什么办法可以回到我的用户的实时应用程序中修复这个错误?

让我参考我的另一个问题,通过这个问题,我发现了这个错误: “核心数据不能满足一个错误”,没有被删除的对象

我写了一个新的问题,因为我觉得这是一个不同的问题 – 尽pipe绝对是相关的。

以下是在后台线程中创build对象的代码:

- (void)friendPickerViewControllerDidChooseFriends:(NSArray *)friends { __ENTERING_METHOD__ if (friends.count > 0) { [[FacebookHelper sharedManager] friendPickerController].navigationController.navigationBar.userInteractionEnabled = NO; [self startProgressIndicator]; [self performSelectorInBackground:@selector(importFriends:) withObject:friends]; } else { [self dismissModalImportViewControllerAnimated];//releases picker delegates, etc } } #pragma mark - #pragma mark Import Friend - (void)importFriends:(NSArray*)friends { __ENTERING_METHOD__ for (NSDictionary<FBGraphUser> *friend in friends) { [self importFriend:friend withCompletion:^(void){ CGFloat friendNumber = [friends indexOfObject:friend]+1; CGFloat friendCount = friends.count; self.importProgress = friendNumber/friendCount; }]; } } - (void)importFriend:(NSDictionary<FBGraphUser>*)friend withCompletion:( void (^) (void) )completionBlock { __ENTERING_METHOD__ Person *myNewPerson = [GetObjectArrayHelper createNewPersonMocSaveNew:YES]; myNewPerson.facebookID = friend.id; myNewPerson.facebookName = friend.name; NSString *nameFirst = [friend.first_name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; NSString *nameLast = [friend.last_name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; NSString *imageID = friend.id; UIImage *pickedImage = nil; if(imageID){ pickedImage = [FacebookHelper imageForObject:imageID]; } DLog(@"pickedImage:%@",pickedImage); if(pickedImage){ [self setImagesForFacebookImage:pickedImage forPerson:myNewPerson]; } //we should ALWAYS have a name [Helper changePerson:myNewPerson firstName:nameFirst lastName:nameLast]; if(completionBlock) { completionBlock(); } } - (void)finishedImporting { __ENTERING_METHOD__ [SVProgressHUD showSuccessWithStatus:[self completeString]]; [self performSelector:@selector(dismissModalImportViewControllerAnimated) withObject:nil afterDelay:SV_PROGRESS_HUD_SUCCESS_DELAY]; } - (void)dismissModalImportViewControllerAnimated { __ENTERING_METHOD__ [Helper mocSave];//THIS SAVES IN THE APP DELEGATE MANAGED OBJECT CONTEXT - [SVProgressHUD dismiss]; [self dismissViewControllerAnimated:YES completion:^(void){ [[FacebookHelper sharedManager] friendPickerController].delegate = nil; [[FacebookHelper sharedManager] friendPickerController].navigationController.navigationBar.userInteractionEnabled = YES; }]; } 

请注意,我关心的对象不是在这里(或在这里调用的方法)中创build的任何对象,而是随后与这些对象关联的对象。

他们为什么“核心数据不能实现故障”崩溃? (我明白为什么在这里或者在这里调用的方法创build的任何对象会得到它)。

另外 – 一旦我找出为什么发生这样的混乱(并修复造成它的代码),我需要修复我的用户的实时应用程序中的stream氓对象。 我真的可以使用一些build议,以及!

根据你的问题和你的意见,你是:

  • 在多个线程上使用单个pipe理对象。
  • 没有采取任何预防措施来处理NSManagedObjectContext不是线程安全的事实。

结果,你越来越奇怪,令人困惑的崩溃。

这正是在这种情况下所期待的。 在多个线程上使用托pipe对象上下文而不采取预防措施基本上是崩溃和混乱的秘诀。 这些崩溃可能没有多大意义,因为你正在破坏上下文的内部状态。

如果要在多个线程上使用上下文,则必须使用队列限制选项( NSMainQueueConcurrencyTypeNSPrivateQueueConcurrencyType )之一,然后必须将使用上下文或从其中提取的任何对象的所有代码放在performBlock:performBlockAndWait: 。 (例外:如果您使用NSMainQueueConcurrencyType并且您知道您的代码位于主线程上,则可以直接使用上下文)。 你也可以使用你自己的locking机制,像NSLock ,但是对于大多数人来说,线程已经够用了。

每个线程使用一个上下文通常会更好,不pipe是作为父/子上下文还是作为独立的上下文,但上面的方法也是可行的。

如果实际上设法保存了伪造对象,唯一真正的办法就是获取这些对象,并将其修复或删除。 如何识别这些对象取决于你的数据模型 – 对于“这个对象废话?”没有通用的testing。 任何检查取决于你的应用程序认为是正确的。