CoreData崩溃“无法在绑定{}中获得'批处理'的值。”重置NSManagedObjectContext时

时间:2018-03-01 15:00:45

标签: core-data

我正在使用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
)

2 个答案:

答案 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 Harringtonhis 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堆栈都会在注销时解除分配。