删除后台moc中的对象然后在主moc中刷新它会导致NSFetchedResultsController更新崩溃

时间:2014-01-05 18:35:23

标签: ios core-data nsfetchedresultscontroller

我遇到了一个我无法理解的NSObjectInaccessibleException

 *** Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0x8c40040 <x-coredata://85B02C1C-1FFC-4CBF-B7AC-EEA259115427/Event/p6>''
*** First throw call stack:
(
    0   CoreFoundation                      0x01aa15e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x018248b6 objc_exception_throw + 44
    2   CoreData                            0x0025733b _PFFaultHandlerLookupRow + 2715
    3   CoreData                            0x00256897 -[NSFaultHandler fulfillFault:withContext:forIndex:] + 39
    4   CoreData                            0x00256473 _PF_FulfillDeferredFault + 259
    5   CoreData                            0x002562c6 _sharedIMPL_pvfk_core + 70
    6   CoreData                            0x0025acd5 -[NSManagedObject(_PFDynamicAccessorsAndPropertySupport) _genericValueForKey:withIndex:flags:] + 85
    7   CoreData                            0x00294781 _PF_Handler_Public_GetProperty + 161
    8   CoreData                            0x00294685 -[NSManagedObject valueForKey:] + 149
    9   Foundation                          0x01471a5a -[NSObject(NSKeyValueCoding) valueForKeyPath:] + 409
    10  Foundation                          0x015079ba -[NSSortDescriptor compareObject:toObject:] + 166
    11  CoreData                            0x00366175 +[NSFetchedResultsController(PrivateMethods) _insertIndexForObject:inArray:lowIdx:highIdx:sortDescriptors:] + 309
    12  CoreData                            0x00360f61 -[NSFetchedResultsController(PrivateMethods) _postprocessInsertedObjects:] + 737
    13  CoreData                            0x00362c44 -[NSFetchedResultsController(PrivateMethods) _postprocessUpdatedObjects:] + 916
    14  CoreData                            0x00363578 -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] + 2152
    15  Foundation                          0x014f7bf9 __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke + 40
    16  CoreFoundation                      0x01afd524 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20
    17  CoreFoundation                      0x01a5500b _CFXNotificationPost + 2859
    18  Foundation                          0x01431951 -[NSNotificationCenter postNotificationName:object:userInfo:] + 98
    19  CoreData                            0x00268173 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 83
    20  CoreData                            0x0030778f -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:] + 367
    21  CoreData                            0x00263e38 -[NSManagedObjectContext(_NSInternalChangeProcessing) _postRefreshedObjectsNotificationAndClearList] + 136
    22  CoreData                            0x002639e4 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 3140
    23  CoreData                            0x00262d99 -[NSManagedObjectContext processPendingChanges] + 41
    24  CoreData                            0x00236fe1 _performRunLoopAction + 321
    25  CoreFoundation                      0x01a694ce __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
    26  CoreFoundation                      0x01a6941f __CFRunLoopDoObservers + 399
    27  CoreFoundation                      0x01a47344 __CFRunLoopRun + 1076
    28  CoreFoundation                      0x01a46ac3 CFRunLoopRunSpecific + 467
    29  CoreFoundation                      0x01a468db CFRunLoopRunInMode + 123
    30  GraphicsServices                    0x039029e2 GSEventRunModal + 192
    31  GraphicsServices                    0x03902809 GSEventRun + 104
    32  UIKit                               0x00592d3b UIApplicationMain + 1225
    33  RefreshDeletedTest                  0x00005d9d main + 141
    34  libdyld.dylib                       0x020df70d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type _NSCoreDataException

这是由特定的代码流引起的:

- (void)deleteObject:(NSManagedObject *)object {
    NSManagedObjectID *objID = object.objectID;
    NSManagedObjectContext *dataProcessingMoc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    dataProcessingMoc.persistentStoreCoordinator = self.managedObjectContext.persistentStoreCoordinator;
    dataProcessingMoc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataProcessingContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:dataProcessingMoc];
    // If I use performBlockAndWait: instead of performBlock: the issue goes away.
    [dataProcessingMoc performBlock:^{
        NSManagedObject *objInDPMoc = [dataProcessingMoc objectWithID:objID];
        NSLog(@"Delete: %@", objInDPMoc);
        [dataProcessingMoc deleteObject:objInDPMoc]; // 1
        [object.managedObjectContext performBlockAndWait:^{
            [object.managedObjectContext refreshObject:object mergeChanges:NO]; // 2
        }];
        [dataProcessingMoc save:NULL]; // 3
    }];
}

- (void)dataProcessingContextDidSave:(NSNotification *)note {
    NSManagedObjectContext *moc = self.managedObjectContext;
    [moc performBlockAndWait:^{ // 3
        [moc mergeChangesFromContextDidSaveNotification:note];
        NSError *error;
        if ([moc hasChanges] && ![moc save:&error]) {
            NSLog(@"Unresolved error %@", error);
            abort();
        }
    }];
}

注意:代码必须看起来很奇怪并且没有多大意义。这是我将实际代码减少到最小错误再现代码的结果。

  1. 删除背景中的对象moc。
  2. 刷新同一个对象,在main moc中变为故障。
  3. 使用NSManagedObjectContextDidSaveNotification保存背景moc并将其更改合并到主moc。
  4. 异常发生在真正的合并之前,在主要的moc调用performBlockAndWait:

    这是崩溃时背景moc的线程堆栈:

    #0  0x02210fb6 in semaphore_wait_trap ()
    #1  0x01e3ccde in _dispatch_thread_semaphore_wait ()
    #2  0x01e3a516 in _dispatch_barrier_sync_f_slow ()
    #3  0x01e3a413 in dispatch_barrier_sync_f ()
    #4  0x0028bf1f in -[NSManagedObjectContext performBlockAndWait:] ()
    #5  0x000037b5 in -[MasterViewController dataProcessingContextDidSave:] at /Users/an0/dev/Projects/iOS/Study/RefreshDeletedTest/RefreshDeletedTest/MasterViewController.m:84
    #6  0x014f7bf9 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke ()
    #7  0x01afd524 in __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ ()
    #8  0x01a5500b in _CFXNotificationPost ()
    #9  0x01431951 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
    #10 0x0027bb2c in -[NSManagedObjectContext(_NSInternalAdditions) _didSaveChanges] ()
    #11 0x0026720f in -[NSManagedObjectContext save:] ()
    #12 0x0000345a in __37-[MasterViewController cleanObjects:]_block_invoke at /Users/an0/dev/Projects/iOS/Study/RefreshDeletedTest/RefreshDeletedTest/MasterViewController.m:78
    #13 0x003047c3 in developerSubmittedBlockToNSManagedObjectContextPerform_privateasync ()
    #14 0x01e4d4b0 in _dispatch_client_callout ()
    #15 0x01e3b07f in _dispatch_queue_drain ()
    #16 0x01e3ae7a in _dispatch_queue_invoke ()
    #17 0x01e3be1f in _dispatch_root_queue_drain ()
    #18 0x01e3c137 in _dispatch_worker_thread2 ()
    #19 0x021d9dab in _pthread_wqthread ()
    

    为什么它会以这种方式崩溃?我的代码真的错了,或者是Core Data的错误吗?

    我无法理解的另一件奇怪的事情是,在这样的崩溃之后,应用程序无法启动,因为它会在启动时崩溃:

    2014-01-05 12:31:34.151 RefreshDeletedTest[3546:70b] *** Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0xa88d060 <x-coredata://93009ECF-EC6E-4B12-BC40-997C4BF3B8DF/Event/p11>''
    *** First throw call stack:
    (
        0   CoreFoundation                      0x01aa05e4 __exceptionPreprocess + 180
        1   libobjc.A.dylib                     0x018238b6 objc_exception_throw + 44
        2   CoreData                            0x0025633b _PFFaultHandlerLookupRow + 2715
        3   CoreData                            0x00255897 -[NSFaultHandler fulfillFault:withContext:forIndex:] + 39
        4   CoreData                            0x00255473 _PF_FulfillDeferredFault + 259
        5   CoreData                            0x002552c6 _sharedIMPL_pvfk_core + 70
        6   CoreData                            0x00259cd5 -[NSManagedObject(_PFDynamicAccessorsAndPropertySupport) _genericValueForKey:withIndex:flags:] + 85
        7   CoreData                            0x00293781 _PF_Handler_Public_GetProperty + 161
        8   CoreData                            0x00293685 -[NSManagedObject valueForKey:] + 149
        9   Foundation                          0x014a8f0a -[NSArray(NSKeyValueCoding) valueForKey:] + 456
        10  Foundation                          0x01470a5a -[NSObject(NSKeyValueCoding) valueForKeyPath:] + 409
        11  Foundation                          0x0149b99d -[NSArray(NSKeyValueCoding) valueForKeyPath:] + 580
        12  CoreData                            0x0035b7e9 -[NSFetchedResultsController performFetch:] + 697
        13  RefreshDeletedTest                  0x00003910 -[MasterViewController fetchedResultsController] + 800
        14  RefreshDeletedTest                  0x0000307e -[MasterViewController numberOfSectionsInTableView:] + 78
        15  UIKit                               0x007e5b94 -[UITableViewRowData(UITableViewRowDataPrivate) _updateNumSections] + 102
        16  UIKit                               0x007e6993 -[UITableViewRowData invalidateAllSections] + 69
        17  UIKit                               0x0065d237 -[UITableView _updateRowData] + 194
        18  UIKit                               0x0065d170 -[UITableView _ensureRowDataIsLoaded] + 45
        19  UIKit                               0x006704b3 -[UITableView numberOfSections] + 35
        20  UIKit                               0x0084d3d3 -[UITableViewController viewWillAppear:] + 103
        21  UIKit                               0x006a8bfa -[UIViewController _setViewAppearState:isAnimating:] + 419
        22  UIKit                               0x006a9108 -[UIViewController __viewWillAppear:] + 114
        23  UIKit                               0x006cb3f5 -[UINavigationController _startTransition:fromViewController:toViewController:] + 800
        24  UIKit                               0x006cc09c -[UINavigationController _startDeferredTransitionIfNeeded:] + 645
        25  UIKit                               0x006cccb9 -[UINavigationController __viewWillLayoutSubviews] + 57
        26  UIKit                               0x00806181 -[UILayoutContainerView layoutSubviews] + 213
        27  UIKit                               0x0e35656f -[UILayoutContainerViewAccessibility(SafeCategory) layoutSubviews] + 50
        28  UIKit                               0x005fc267 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355
        29  libobjc.A.dylib                     0x0183581f -[NSObject performSelector:withObject:] + 70
        30  QuartzCore                          0x045802ea -[CALayer layoutSublayers] + 148
        31  QuartzCore                          0x045740d4 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
        32  QuartzCore                          0x04580235 -[CALayer layoutIfNeeded] + 160
        33  UIKit                               0x006b7613 -[UIViewController window:setupWithInterfaceOrientation:] + 304
        34  UIKit                               0x005d6177 -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] + 5212
        35  UIKit                               0x005d4d16 -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:] + 82
        36  UIKit                               0x005d4be8 -[UIWindow _setRotatableViewOrientation:updateStatusBar:duration:force:] + 117
        37  UIKit                               0x005d4c70 -[UIWindow _setRotatableViewOrientation:duration:force:] + 67
        38  UIKit                               0x005d3d0a __57-[UIWindow _updateToInterfaceOrientation:duration:force:]_block_invoke + 120
        39  UIKit                               0x005d3c6c -[UIWindow _updateToInterfaceOrientation:duration:force:] + 400
        40  UIKit                               0x005d49c3 -[UIWindow setAutorotates:forceUpdateInterfaceOrientation:] + 870
        41  UIKit                               0x005d7fb6 -[UIWindow setDelegate:] + 449
        42  UIKit                               0x006a9737 -[UIViewController _tryBecomeRootViewControllerInWindow:] + 180
        43  UIKit                               0x005cdc1c -[UIWindow addRootViewControllerViewIfPossible] + 609
        44  UIKit                               0x005cdd97 -[UIWindow _setHidden:forced:] + 312
        45  UIKit                               0x005ce02d -[UIWindow _orderFrontWithoutMakingKey] + 49
        46  UIKit                               0x0e332c66 -[UIWindowAccessibility(SafeCategory) _orderFrontWithoutMakingKey] + 77
        47  UIKit                               0x005d889a -[UIWindow makeKeyAndVisible] + 65
        48  UIKit                               0x0058bcd0 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1851
        49  UIKit                               0x005903a8 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 824
        50  UIKit                               0x005a487c -[UIApplication handleEvent:withNewEvent:] + 3447
        51  UIKit                               0x005a4de9 -[UIApplication sendEvent:] + 85
        52  UIKit                               0x00592025 _UIApplicationHandleEvent + 736
        53  GraphicsServices                    0x039032f6 _PurpleEventCallback + 776
        54  GraphicsServices                    0x03902e01 PurpleEventCallback + 46
        55  CoreFoundation                      0x01a1bd65 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
        56  CoreFoundation                      0x01a1ba9b __CFRunLoopDoSource1 + 523
        57  CoreFoundation                      0x01a4677c __CFRunLoopRun + 2156
        58  CoreFoundation                      0x01a45ac3 CFRunLoopRunSpecific + 467
        59  CoreFoundation                      0x01a458db CFRunLoopRunInMode + 123
        60  UIKit                               0x0058fadd -[UIApplication _run] + 840
        61  UIKit                               0x00591d3b UIApplicationMain + 1225
        62  RefreshDeletedTest                  0x0000508d main + 141
        63  libdyld.dylib                       0x020de70d start + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type _NSCoreDataException
    

    以下是您可以自行查看问题的示例项目:http://d.pr/f/y3VQ

2 个答案:

答案 0 :(得分:4)

在多线程环境中无法避免此问题。

只要您在同一层次结构级别上有两个不同的上下文(无论是父子架构还是直接连接到商店),您可能会遇到一个上下文删除了一个对象(并且已提交对商店的更改)和另一个尝试在合并更改之前访问此对象 当父上下文提交更改到商店并且其子项尝试访问他作为错误保留的已删除项时,也可能发生这种情况 通常,在提交之前的上下文之间不会自动传播更改的每个位置,都有可能获得此异常。

如果您可以管道您的上下文(store-context1-context2 -...)并且只从链中的最终上下文中删除,则可以避免此问题。

您可以设计一些算法来延迟删除操作,这样只有在没有其他上下文使用特定项目时才会提交它们,但这需要您进行大量的簿记。

您可以通过获取完整的(无故障)对象或您将要处理的整个子图(使用FRC时无法完成)来减少上下文之间的冲突,并对这些对象进行操作。

答案 1 :(得分:0)

WWDC 2015 220 What's New in Core Data中,随着iOS 9的发布以及NSManagedObjectContext的{​​{3}}属性的解决。

当前,shouldDeleteInaccessibleFaults默认为是。 如果遇到故障,我们会将故障标记为已删除,并且所有缺少的属性将为null,nil或零。 这使您的应用可以继续使用该对象,并将其视为已删除对象。 您将不再崩溃,而仅需继续操作并向用户显示他们期望看到的内容。