我正在使用JSQCoreDataKit来设置核心数据堆栈。
我的设置包括两个CoreData堆栈,一个由SQLite数据库支持,第二个仅在内存中。
在我的应用程序中,在注销期间,我正在重置两个堆栈 - 请参阅代码:https://github.com/jessesquires/JSQCoreDataKit/blob/develop/Source/CoreDataStack.swift#L142
当重置内存核心数据堆栈时,我的应用程序有时在正在重置主NSManagedObjectContext的行上崩溃。我无法在本地重现它。
崩溃邮件本身是Google无法找到任何结果的内容:
*** 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
)
答案 0 :(得分:1)
很难确定,但堆栈跟踪提供了线索。您可以在此处重置上下文:
=IIf(Fields!IncStatusActionType.Value = "TH",
CLng(DateDiff(DateInterval.Hour,CDATE(Fields!ActivityDate.Value), CDATE(Globals!ExecutionTime))).ToString("00") & ":" &
CLng(DateDiff(DateInterval.Minute,CDATE(Fields!ActivityDate.Value), CDATE(Globals!ExecutionTime)) Mod 60).ToString("00") & ":" &
CLng(DateDiff(DateInterval.Second,CDATE(Fields!ActivityDate.Value), CDATE(Globals!ExecutionTime)) Mod 60).ToString("00"), "")
更深层次,发生这种情况:
34 CoreData 0x000000010d7cdedf -[NSManagedObjectContext reset] + 1119
接下来是其他获取的结果控制器内容,包括
之类的内容26 CoreData 0x000000010d8a6207 -[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:] + 119
这表明您正在重置上下文,而22 CoreData 0x000000010d8a1e03 -[NSFetchedResultsController(PrivateMethods) _computeSectionInfo:error:] + 691
仍在尝试让您的UI保持最新状态。它注意到由重置引起的更改并尝试处理这些更改,但由于重置正在进行,因此会失败。
这可能是NSFetchedResultsController
难以安全使用的原因的一个例子。如果您有任何以任何方式使用或引用上下文的对象,reset
可能会造成麻烦。在调用reset
之前,您可能需要确保使用NSFetchedResultsController
的任何UI完全内存不足。
答案 1 :(得分:0)
正如Tom Harrington中his answer所指出的那样,NSFetchedResultsController
的一个特定实例在主要上下文被重置时被通知并且可能尝试执行失败的提取,从而导致被抛出的异常。
有趣的是,只有在使用内存存储时才会发生这种情况。切换到SQLite存储时,问题就消失了。由于出于性能原因我想继续使用内存存储,我想出了以下解决方法。
为了防止NSFetchedResultsController
崩溃,我让FRC停止在上下文(和整个CoreData堆栈)重置之前观察上下文中的更改。
这是通过从重置CoreData堆栈的方法发布通知并将FRC的委托设置为nil
来完成的。以下代码来自使用此特定FRC的ViewController。
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的委托属性,因为包括FRC在内的整个UIViewController堆栈都会在注销时解除分配。