CoreData崩溃“无法在绑定{}中获取'批处理'的值。”重置NSManagedObjectContext时
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CoreData崩溃“无法在绑定{}中获取'批处理'的值。”重置NSManagedObjectContext时相关的知识,希望对你有一定的参考价值。
我正在使用JSQCoreDataKit来设置Core Data堆栈。
我的设置包括两个CoreData堆栈,一个由SQLite数据库支持,第二个仅在内存中。
在我的应用程序中,在注销期间,我正在重置两个堆栈 - 请参阅代码:https://github.com/jessesquires/JSQCoreDataKit/blob/develop/Source/CoreDataStack.swift#L142
重置内存核心数据堆栈时,我的应用程序有时会在重置主NSManagedObjectContext的行上崩溃。我无法在本地重现它。
崩溃邮件本身是谷歌没有找到任何结果:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't get value for 'batch' in bindings {
}.'
*** First throw call stack:
(
0 CoreFoundation 0x000000010dd3312b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010cd6bf41 objc_exception_throw + 48
2 Foundation 0x000000010898b3de -[NSComparisonPredicate rightExpression] + 0
3 Foundation 0x000000010898c11f -[NSComparisonPredicate evaluateWithObject:substitutionVariables:] + 274
4 CoreData 0x000000010d769a08 -[NSDictionaryStoreMap handleFetchRequest:] + 504
5 CoreData 0x000000010d768bf3 -[NSMappedObjectStore executeFetchRequest:withContext:] + 243
6 CoreData 0x000000010d768a91 -[NSMappedObjectStore executeRequest:withContext:error:] + 193
7 CoreData 0x000000010d80c08b __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke + 1691
8 CoreData 0x000000010d8044a6 __55-[NSPersistentStoreCoordinator _routeHeavyweightBlock:]_block_invoke + 86
9 CoreData 0x000000010d818519 gutsOfBlockToNSPersistentStoreCoordinatorPerform + 201
10 libdispatch.dylib 0x0000000110fcb33d _dispatch_client_callout + 8
11 libdispatch.dylib 0x0000000110fd2235 _dispatch_queue_barrier_sync_invoke_and_complete + 392
12 CoreData 0x000000010d803e35 _perform + 213
13 CoreData 0x000000010d8041bb -[NSPersistentStoreCoordinator _routeHeavyweightBlock:] + 283
14 CoreData 0x000000010d70aac4 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 660
15 CoreData 0x000000010d7090e4 -[NSManagedObjectContext executeFetchRequest:error:] + 564
16 CoreData 0x000000010d78794a _faultBatchAtIndex + 714
17 CoreData 0x000000010d789a4a -[_PFBatchFaultingArray retainedObjectAtIndex:] + 74
18 CoreData 0x000000010d789b32 -[_PFBatchFaultingArray objectAtIndex:] + 50
19 CoreData 0x000000010d8a2318 __72-[NSFetchedResultsController(PrivateMethods) _computeSectionInfo:error:]_block_invoke + 200
20 CoreData 0x000000010d74c748 developerSubmittedBlockToNSManagedObjectContextPerform + 168
21 CoreData 0x000000010d74c61f -[NSManagedObjectContext performBlockAndWait:] + 239
22 CoreData 0x000000010d8a1e03 -[NSFetchedResultsController(PrivateMethods) _computeSectionInfo:error:] + 691
23 CoreData 0x000000010d8a665b __82-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:]_block_invoke + 1083
24 CoreData 0x000000010d74c748 developerSubmittedBlockToNSManagedObjectContextPerform + 168
25 CoreData 0x000000010d74c61f -[NSManagedObjectContext performBlockAndWait:] + 239
26 CoreData 0x000000010d8a6207 -[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:] + 119
27 CoreFoundation 0x000000010dcceeac __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
28 CoreFoundation 0x000000010dccedaa _CFXRegistrationPost + 442
29 CoreFoundation 0x000000010dcceaf2 ___CFXNotificationPost_block_invoke + 50
30 CoreFoundation 0x000000010dc90792 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1826
31 CoreFoundation 0x000000010dc8f90c _CFXNotificationPost + 652
32 Foundation 0x00000001089548f2 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
33 CoreData 0x000000010d735725 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 773
34 CoreData 0x000000010d7cdedf -[NSManagedObjectContext reset] + 1119
35 JSQCoreDataKit 0x000000010906b3c8 _T014JSQCoreDataKit04CoreB5StackC5resetySo13DispatchQueueC02onH0_yAA0E6ResultOc10completiontFyycfU_ + 88
36 JSQCoreDataKit 0x000000010906b3ec _T014JSQCoreDataKit04CoreB5StackC5resetySo13DispatchQueueC02onH0_yAA0E6ResultOc10completiontFyycfU_TA + 12
37 JSQCoreDataKit 0x0000000109065599 _T0Ix_IyB_TR + 41
38 CoreData 0x000000010d74c748 developerSubmittedBlockToNSManagedObjectContextPerform + 168
39 CoreData 0x000000010d74c61f -[NSManagedObjectContext performBlockAndWait:] + 239
40 JSQCoreDataKit 0x000000010906ae2d _T014JSQCoreDataKit04CoreB5StackC5resetySo13DispatchQueueC02onH0_yAA0E6ResultOc10completiontF + 317
41 MyApp 0x000000010c4f362a _T08MyApp14DataRepositoryV09resetCoreD5Stackyyyc10completion_tFZyAA19AsyncBlockOperationCcfU0_ + 106
42 MyApp 0x000000010c717761 _T08MyApp19AsyncBlockOperationC5startyyF + 433
43 MyApp 0x000000010c7177c4 _T08MyApp19AsyncBlockOperationC5startyyFTo + 36
44 Foundation 0x0000000108983577 __NSOQSchedule_f + 369
45 libdispatch.dylib 0x0000000110fcb33d _dispatch_client_callout + 8
46 libdispatch.dylib 0x0000000110fd65f9 _dispatch_main_queue_callback_4CF + 628
47 CoreFoundation 0x000000010dcf5e39 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
48 CoreFoundation 0x000000010dcba462 __CFRunLoopRun + 2402
49 CoreFoundation 0x000000010dcb9889 CFRunLoopRunSpecific + 409
50 GraphicsServices 0x0000000112dfc9c6 GSEventRunModal + 62
51 UIKit 0x000000010a0875d6 UIApplicationMain + 159
52 GoOut 0x00000001061e3857 main + 55
53 libdyld.dylib 0x0000000111047d81 start + 1
)
很难确定,但堆栈跟踪提供了线索。这是您重置上下文的位置:
34 CoreData 0x000000010d7cdedf -[NSManagedObjectContext reset] + 1119
更深层次,这种情况发生:
26 CoreData 0x000000010d8a6207 -[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:] + 119
接下来是其他获取的结果控制器的东西,包括像
22 CoreData 0x000000010d8a1e03 -[NSFetchedResultsController(PrivateMethods) _computeSectionInfo:error:] + 691
这表明你正在重置上下文,而NSFetchedResultsController
仍然试图让你的UI保持最新。它注意到由重置引起的更改并尝试处理这些更改,但由于重置正在进行,因此会失败。
这可能是为什么reset
难以安全使用的一个例子。如果您有任何以任何方式使用或引用上下文的对象,reset
可能会造成麻烦。在调用NSFetchedResultsController
之前,您可能需要确保使用reset
的任何UI都完全没有内存。
The possible root cause
正如Tom Harrington在his answer中指出的那样,它是NSFetchedResultsController
的一个特定实例,当主要上下文被重置时可能会被通知并且可能尝试执行失败的获取,从而导致异常被抛出。
有趣的是,只有在使用内存存储时才会发生这种情况。切换到SQLite存储时,问题就消失了。由于出于性能原因我想继续使用内存存储,我想出了以下解决方法。
The workaround
为了防止NSFetchedResultsController
崩溃,我让FRC在上下文(和整个CoreData堆栈)重置之前停止观察上下文中的更改。
这是通过从重置CoreData堆栈的方法发布通知并将FRC的委托设置为nil
来完成的。以下代码来自ViewController,其中使用了此特定FRC。
private func setupObservers() {
NotificationCenter.default.addObserver(
self,
selector: #selector(didReceiveDataRepositoryWillResetNotification(_:)),
name: Notification.Name.DataRepository.WillResetCoreData,
object: nil
)
}
@objc private func didReceiveDataRepositoryWillResetNotification(_ notification: Notification) {
// HAX: Workaround for FRC throwing an exception when linked to a context backed by in-memory store
// More info: https://stackoverflow.com/q/49052482/1161723
fetchedResultsController?.delegate = nil
}
请注意,我没有在任何地方再次设置FRC的委托属性,因为无论如何整个UIViewController堆栈(包括FRC)在注销时已取消分配。
以上是关于CoreData崩溃“无法在绑定{}中获取'批处理'的值。”重置NSManagedObjectContext时的主要内容,如果未能解决你的问题,请参考以下文章