重置存储时核心数据崩溃:“无法从此 NSManagedObjectContext 的协调器访问对象的持久存储”

Posted

技术标签:

【中文标题】重置存储时核心数据崩溃:“无法从此 NSManagedObjectContext 的协调器访问对象的持久存储”【英文标题】:Core data crash when resetting the store: 'Object's persistent store is not reachable from this NSManagedObjectContext's coordinator' 【发布时间】:2016-11-14 14:33:16 【问题描述】:

在我用 Swift 编写的 ios 应用程序中尝试删除 Core 数据的持久存储时,我遇到了崩溃。流程很简单:当我从应用程序中注销时,我删除了商店:

destroyPersistentStoreAtURL

我在应用程序中使用原生 Core Data 实现,并且每次访问托管对象都是使用 performBlock/performBlockAndWait 进行的。此外,这些操作位于NSOperationQueue 中。流程如下:

    注销 cancelAllOperations & waitUntilAllOperationsAreFinished 在实现performBlocks 的队列中 maxConcurrentOperationCount = 1performBlocks 的队列中 最后,我在前面的NSOperationQueue 中添加了一个销毁持久存储的操作

有时,我遇到了崩溃,我不明白为什么。据我所知,它与 managedObjectsIDs 和保留有关。看看:

2016-11-14 15:51:58.053 ******[3912:179074] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Object's persistent store is not reachable from this NSManagedObjectContext's coordinator'
*** First throw call stack:
(
	0   CoreFoundation                      0x000000010ca0f34b __exceptionPreprocess + 171
	1   libobjc.A.dylib                     0x000000010c05321e objc_exception_throw + 48
	2   CoreData                            0x000000010c5683b2 _PFRetainedObjectIDCore + 1074
	3   CoreData                            0x000000010c5507fc -[NSManagedObjectContext objectWithID:] + 668
	4   CoreData                            0x000000010c590264 _faultBatchAtIndex + 1524
	5   CoreData                            0x000000010c59217a -[_PFBatchFaultingArray retainedObjectAtIndex:] + 74
	6   CoreData                            0x000000010c592262 -[_PFBatchFaultingArray objectAtIndex:] + 50
	7   CoreData                            0x000000010c67d9de __72-[NSFetchedResultsController(PrivateMethods) _computeSectionInfo:error:]_block_invoke + 190
	8   CoreData                            0x000000010c55adc7 developerSubmittedBlockToNSManagedObjectContextPerform + 199
	9   CoreData                            0x000000010c55ac7f -[NSManagedObjectContext performBlockAndWait:] + 255
	10  CoreData                            0x000000010c67d3b6 -[NSFetchedResultsController(PrivateMethods) _computeSectionInfo:error:] + 694
	11  CoreData                            0x000000010c681d75 __82-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:]_block_invoke + 1077
	12  CoreData                            0x000000010c55adc7 developerSubmittedBlockToNSManagedObjectContextPerform + 199
	13  CoreData                            0x000000010c55ac7f -[NSManagedObjectContext performBlockAndWait:] + 255
	14  CoreData                            0x000000010c681927 -[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:] + 119
	15  CoreFoundation                      0x000000010c9ad19c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
	16  CoreFoundation                      0x000000010c9ad09b _CFXRegistrationPost + 427
	17  CoreFoundation                      0x000000010c9ace02 ___CFXNotificationPost_block_invoke + 50
	18  CoreFoundation                      0x000000010c96fea2 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 2018
	19  CoreFoundation                      0x000000010c96ef3b _CFXNotificationPost + 667
	20  Foundation                          0x000000010bb1b0ab -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
	21  CoreData                            0x000000010c5432b0 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 704
	22  CoreData                            0x000000010c562b50 -[NSManagedObjectContext(_NSInternalNotificationHandling) _processChangedStoreConfigurationNotification:] + 2976
	23  CoreData                            0x000000010c5d97ed __95-[NSManagedObjectContext(_NSInternalNotificationHandling) _sendOrEnqueueNotification:selector:]_block_invoke + 109
	24  CoreData                            0x000000010c55adc7 developerSubmittedBlockToNSManagedObjectContextPerform + 199
	25  libdispatch.dylib                   0x000000010e0250cd _dispatch_client_callout + 8
	26  libdispatch.dylib                   0x000000010e0058d6 _dispatch_main_queue_callback_4CF + 406
	27  CoreFoundation                      0x000000010c9d34f9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
	28  CoreFoundation                      0x000000010c998f8d __CFRunLoopRun + 2205
	29  CoreFoundation                      0x000000010c998494 CFRunLoopRunSpecific + 420
	30  GraphicsServices                    0x000000010f5d0a6f GSEventRunModal + 161
	31  UIKit                               0x000000010a050964 UIApplicationMain + 159
	32  ******                              0x000000010817e932 main + 114
	33  libdyld.dylib                       0x000000010e07168d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

非常感谢任何帮助!

【问题讨论】:

【参考方案1】:

您需要重置此操作之前使用的managedObjectContext

致电managedObjectContext.reset()

【讨论】:

完成了,现在已经解决了一段时间(请参阅我在最后一个答案中的最后一条评论)。不过,感谢您的回复。 @nick3389 - 我们什么时候必须调用重置函数? @nOObiOS 在你销毁你的 persistentStore 之前。【参考方案2】:

我有同样的问题和 Tom 的暗示,假设脏对象——那些曾经存在于旧存储中的对象——在我从协调器中删除持久存储之后仍然是托管对象上下文的一部分。在我的例子中,我实现了一个“恢复到上次保存的文档版本”,它需要确保首先丢弃这些脏对象。

[_managedObjectContext reset]
[_managedObjectContext.persistentStoreCoordinator removePersistentStore:_store error:outError]

如果您的代码中仍有对这些对象的引用,object.managedObjectContext 将为 nil — 这是一个很好的恢复提示。

【讨论】:

【参考方案3】:

错误告诉您,在销毁从中获取托管对象的持久存储后,您仍在尝试使用托管对象。这肯定会导致这次崩溃。

不可能确切地说出这是在哪里发生的,但是如果您在删除存储后保留对托管对象的任何引用,您就会得到这个。如果最终您仍在尝试使用不再具有持久性存储的托管对象,则取消操作、使用performBlock 等不会产生任何影响。

【讨论】:

那么,我猜唯一正确的答案是将销毁操作放入队列中?? 唯一正确的答案是确保在销毁持久存储后永远不要尝试使用现有的托管对象。根据您的问题,这是否意味着调整您的队列或其他内容是不可能的。 问题仍然存在,我已经验证它是由 NSFetchedResultsController 引起的。我的过程是我保留对 NSFetchedResultsController 的引用,并在销毁商店之前将其设为 nil 以及它的委托。这个可以吗?我真的找不到其他可以做的事情,因为没有其他对这个 NSFetchedResultsController 对象的引用。 当您说“我保留对 NSFetchedResultsController 的引用并将其设为 nil”时,您似乎在自相矛盾,因为您不能保留引用 并且 make参考为零。 问题已解决。在销毁持久存储之前,我没有重置上下文:mainQueueContext.reset(),所以有时我会遇到卡在内存中的对象的问题。感谢您的帮助!【参考方案4】:

@汤姆

是的,你是对的。所以我给你举个例子:

let queue = NSOperationQueue

queue.addOperationWithBlock
  let moc = newPrivateQueueManagedObjectContext()
  moc.performBlock 
    //some work to do on the context

然后有时我会销毁商店,但在此之前我取消了上述队列上的操作。不过,有时我会看到崩溃...

【讨论】:

以上是关于重置存储时核心数据崩溃:“无法从此 NSManagedObjectContext 的协调器访问对象的持久存储”的主要内容,如果未能解决你的问题,请参考以下文章

崩溃后核心数据为空

RestKit 重置核心数据存储

Parse:如何重置本地数据存储?

在 performBlock 中重置我的 NSManagedObjectContext 时,iOS 8 应用程序崩溃

重置 Firebase 缓存

核心数据和多线程在保存时崩溃