Multithreading iOS 8.3上的CoreData多线程崩溃

Multithreading iOS 8.3上的CoreData多线程崩溃,multithreading,core-data,Multithreading,Core Data,将设备/xCode更新到iOS 8.3后,当我进行后台更新时,我的应用程序开始崩溃。 以下是我的managedObjectContext/persistentStoreCoordinator方法: - (NSManagedObjectContext *)managedObjectContext { NSThread *thisThread = [NSThread currentThread]; if (thisThread == [NSThread mainThread]) {

将设备/xCode更新到iOS 8.3后,当我进行后台更新时,我的应用程序开始崩溃。 以下是我的managedObjectContext/persistentStoreCoordinator方法:

- (NSManagedObjectContext *)managedObjectContext {
    NSThread *thisThread = [NSThread currentThread];
    if (thisThread == [NSThread mainThread]) {
        return self.mainContext;
    }

    NSString * threadKey = [NSString stringWithFormat:@"%p", thisThread];
    NSManagedObjectContext * threadContext = nil;
    @synchronized(self.managedObjectContexts) {
        threadContext = self.managedObjectContexts[threadKey];
    }

    if (!threadContext) {
        threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        threadContext.parentContext = self.mainContext;
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:threadContext];

        @synchronized(self.managedObjectContexts) {
            [self.managedObjectContexts setObject:threadContext forKey:threadKey];
        }
    }

    return threadContext;
}

+ (NSString*)managedObjectContextKeyForThread:(NSThread*)thread {
return [NSString stringWithFormat:@"%i", (int)thread];
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (!persistentStoreCoordinator) {
    NSManagedObjectModel *objectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:self.modelURL];

    if(objectModel) {
        NSPersistentStoreCoordinator *storeCoordinator = [[NSPersistentStoreCoordinator alloc]
                                                          initWithManagedObjectModel:objectModel];
        NSDictionary * options = @{NSMigratePersistentStoresAutomaticallyOption : @(YES),
                                   NSInferMappingModelAutomaticallyOption : @(YES)
                                   };
        NSError* error = nil;
        if ([storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL
                                                 options:options error:&error])
        {
            persistentStoreCoordinator = storeCoordinator;
        } else {
            NSError *err = nil;
            [[NSFileManager defaultManager] removeItemAtURL:self.storeURL error:&err];
            if ([storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL
                                                     options:options error:&error])
            {
                [[NSNotificationCenter defaultCenter] postNotificationName:kDatabaseRecreatedNotificationKey object:nil];
                persistentStoreCoordinator = storeCoordinator;
            }
        }
    }
}

return persistentStoreCoordinator;
}
它在contextDidSave方法中崩溃,并显示错误消息:

在调试导航器中的第一个异常断点中,它又显示了一行“developerSubmittedBlockToNSManagedObjectContextPerform”

我的代码有什么问题?它在8.3之前运行良好。也许,苹果增加了新的规则?
谢谢你的帮助。

8.3发布后,我也遇到了这种情况。如果您的案例与我的类似,那么您在viewDidLoad中设置了self.mainContext(您没有显示ivar的设置位置)。但我可以在调试器中看到,现在在viewDidLoad之前调用fetchedResultsController。我的解决方案是将我的等效self.mainContext的设置移动到init方法中,在我的例子中是initWithCoder。

经过大量的工作和头痛之后,我转移到并实现了我的主要目标-使用核心数据更新背景数据。

不幸的是,这不是我的情况。我的mainContext初始化在ApplicationIDFinishLaunchingWithOptions方法中。我不确定问题的原因是什么。但是,您并不需要为每个线程提供单独的托管对象上下文,这是iOS<5的过时方法。现在,您可以只使用两个上下文:一个带有
NSMainQueueConcurrencyType
的上下文用于主线程,另一个(父上下文)带有
NSPrivateQueueConcurrencyType
的上下文用于后台处理。然后,您可以使用上下文的
performBlock
方法来确保事情在正确的线程上执行。这篇文章可能会有帮助: