崩溃:NSInternalInconsistencyException - 无效的rowCache行为nil

Ste*_*ani 10 concurrency core-data objective-c ios

我在iOS 8.1上遇到CoreData并发问题.

我正在为崩溃获得以下堆栈跟踪:

NSInternalInconsistencyException - Invalid rowCache row is nil

0     CoreFoundation                        0x0000000183b6659c __exceptionPreprocess + 132
1     libobjc.A.dylib                       0x00000001942640e4 objc_exception_throw + 56
2     CoreData                              0x000000018385b8b8 -[NSSQLCore _newRowCacheRowForToManyUpdatesForRelationship:rowCacheOriginal:originalSnapshot:value:added:deleted:sourceRowPK:properties:sourceObject:newIndexes:reorderedIndexes:] + 6668
3     CoreData                              0x00000001838fbea0 -[NSSQLCore recordToManyChangesForObject:inRow:usingTimestamp:inserted:] + 2604
4     CoreData                              0x0000000183857638 -[NSSQLCore prepareForSave:] + 1052
5     CoreData                              0x00000001838569b4 -[NSSQLCore saveChanges:] + 520
6     CoreData                              0x000000018381f078 -[NSSQLCore executeRequest:withContext:error:] + 716
7     CoreData                              0x00000001838e6254 __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke + 4048
8     CoreData                              0x00000001838ed654 gutsOfBlockToNSPersistentStoreCoordinatorPerform + 176
9     libdispatch.dylib                     0x00000001948a936c _dispatch_client_callout + 12
10   libdispatch.dylib                      0x00000001948b26e8 _dispatch_barrier_sync_f_invoke + 72
11   CoreData                               0x00000001838e0cb4 _perform + 176
12   CoreData                               0x000000018381ec34 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 296
13   CoreData                               0x0000000183845400 -[NSManagedObjectContext save:] + 1280
Run Code Online (Sandbox Code Playgroud)

这种崩溃发生在几个地方(大约20个),但在我的数据导入功能中最为突出,它导入1000个记录并保存每100个记录.

关于我的CoreData设置的一些注意事项:

  • 我正在使用此博客文章中"Stack#3"
  • 我的所有托管对象更新/保存代码都是在a上完成的 performBlock:
  • 崩溃都在背景环境中

发生所有这些保存的代码具有以下基本模式:

[backgroundContext performBlock:^{
    ...
    NSArray *result = [backgroundContext fetch...];
    ...

    if ([backgroundContext save:&error]) { // <-- App is crashing here

    }
}];
Run Code Online (Sandbox Code Playgroud)

据我所知,NSPersistentStore后面应该没有任何并发​​问题,backgroundContext但这就是崩溃告诉我的.

此外,这仅发生在我的用户群的不到0.02%.这是非常罕见的(我无法重现),但用户能够从这种不删除并重新安装应用程序恢复.它将一直打开并为他们崩溃.

请注意,这仅适用于64位iOS 8.1.X - iOS 7.X和8.0.X没有出现此行为,我没有看到比iPhone 5s更早的版本.


澄清:删除持久性商店可以修复所有用户的此问题.这似乎表明它不是并发问题.


创建商店和上下文.

[_persistenStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                     configuration:nil
                                               URL:[DatabaseManager storeURL]
                                           options:@{NSMigratePersistentStoresAutomaticallyOption:@YES,
                                                     NSInferMappingModelAutomaticallyOption:@YES}
                                             error:&error];
Run Code Online (Sandbox Code Playgroud)

创建上下文

_backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_backgroundContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[_backgroundContext setPersistentStoreCoordinator:_persistenStoreCoordinator];
if ([_backgroundContext respondsToSelector:@selector(setName:)]) {
    [_backgroundContext setName:@"DatabaseManager.BackgroundQueue"];
}

_mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_mainContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[_mainContext setPersistentStoreCoordinator:_persistenStoreCoordinator];
if ([_mainContext respondsToSelector:@selector(setName:)]) {
    [_mainContext setName:@"DatabaseManager.MainQueue"];
}

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(mainContextDidSave:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:_mainContext];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(backgroundContextDidSave:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:_backgroundContext];
Run Code Online (Sandbox Code Playgroud)

倾听变化

- (void) mainContextDidSave:(NSNotification *)notification
{
    [_backgroundContext performBlock:^{
        [self->_backgroundContext mergeChangesFromContextDidSaveNotification:notification];
    }];
}

- (void) backgroundContextDidSave:(NSNotification*)notification
{
    [_mainContext performBlock:^{
        NSArray* updated = [notification.userInfo valueForKey:NSUpdatedObjectsKey];

        // Fault all objects that will be updated.
        for (NSManagedObject* obj in updated) {
            NSManagedObject* mainThreadObject = [self->_mainContext objectWithID:obj.objectID];
            [mainThreadObject willAccessValueForKey:nil];
        }

        [self->_mainContext mergeChangesFromContextDidSaveNotification:notification];
    }];
}
Run Code Online (Sandbox Code Playgroud)

如何在每个上下文上执行代码.我把一个街区传到这里:

- (void)executeBackgroundOperation:(void (^)(NSManagedObjectContext *))operation {

    NSAssert(operation, @"No Background operation to perform");

    [_backgroundContext performBlock:^{
        operation(self->_backgroundContext);
    }];
}

- (void)executeMainThreadOperation:(void (^)(NSManagedObjectContext *))operation {
    NSAssert(operation, @"No Main Thread operation to perform");

    [_mainContext performBlock:^{
        operation(self->_mainContext);
    }];
}
Run Code Online (Sandbox Code Playgroud)

崩溃报告中唯一具有其中一个的其他线程lock是两个Javascript线程,如下所示:

0   libsystem_kernel.dylib 0x3a77cb38 __psynch_cvwait + 24
1   libsystem_pthread.dylib 0x3a7fa2dd pthread_cond_wait + 38
2   libc++.1.dylib 0x39a11e91 _ZNSt3__118condition_variable4waitERNS_11unique_lockINS_5mutexEEE + 34
3   JavaScriptCore 0x2dcd4cb5 _ZN3JSC8GCThread16waitForNextPhaseEv + 102
4   JavaScriptCore 0x2dcd4d19 _ZN3JSC8GCThread12gcThreadMainEv + 50
5   JavaScriptCore 0x2db09597 _ZN3WTFL19wtfThreadEntryPointEPv + 12
6   libsystem_pthread.dylib 0x3a7f9e93 _pthread_body + 136
7   libsystem_pthread.dylib 0x3a7f9e07 _pthread_start + 116
8   libsystem_pthread.dylib 0x3a7f7b90 thread_start + 6
Run Code Online (Sandbox Code Playgroud)

Wil*_*con 3

您认为这可能不是并发问题是正确的。当迁移未正确完成时,删除和安装应用程序通常可以修复核心数据错误。

如果您发布了应用程序,更改了核心数据模型,然后发布了更新(没有迁移),这可能是崩溃的根源。

请按照本教程进行操作,看看它是否可以解决您的问题。http://www.raywenderlich.com/27657/how-to-perform-a-lightweight-core-data-migration