重置存储时核心数据崩溃:“无法从此 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 = 1
在performBlocks
的队列中
最后,我在前面的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 的协调器访问对象的持久存储”的主要内容,如果未能解决你的问题,请参考以下文章