需要帮助设置后台托管对象上下文。在 FRC controllerDidChangeContent 上获取异常

Posted

技术标签:

【中文标题】需要帮助设置后台托管对象上下文。在 FRC controllerDidChangeContent 上获取异常【英文标题】:Need help setting up background managed object context. Getting exception on FRC controllerDidChangeContent 【发布时间】:2014-03-02 15:03:26 【问题描述】:

我有一个包含两个托管对象上下文的应用:

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSManagedObjectContext *backgroundContext;

我的一个视图控制器是一个UITableView 控制器,它响应NSFetchedResultsControllerDelegate。当我(从远程 Web 服务)获取对象时,我想在后台线程上处理数据,将更改合并到我的主 managedObjectContext 并更新 UI。

在我当前的设置下,当我尝试获取新对象时出现以下异常。

CoreData: error: Serious application error.  An exception was caught from the delegate of   NSFetchedResultsController during a call to -controllerDidChangeContent:.  *** -[__NSArrayM  insertObject:atIndex:]: object cannot be nil with userInfo (null)

此异常在以下位置引发:

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 

    [self.tableView endUpdates];


我的托管对象上下文是在一个名为 AppController 的单例类中创建的。目前看起来是这样的:

- (id)init     
    self = [super init];
    if (self) 
        sharedInstance = self;

        // Registers NSManagedObjectContextDidSaveNotification 
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:self.managedObjectContext];

    

    return self;


- (void)mergeChanges:(NSNotification *)notification 

    //should tell the main thread moc to run on the main thread, and merge in the changes there
    [self.managedObjectContext  performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)  withObject:notification waitUntilDone:YES];




- (void)saveContext     
    NSError *childError = nil;
    [self.backgroundContext save:&childError];

    [self.managedObjectContext performBlock:^
        NSError *parentError = nil;
        [self.managedObjectContext save:&parentError];
    ];



// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
- (NSManagedObjectContext *)managedObjectContext 
    if (_managedObjectContext != nil) 
        return _managedObjectContext;
    

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) 
        _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
        self.backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType];
        self.backgroundContext.parentContext = self.managedObjectContext;
    
    return _managedObjectContext;

对我缺少什么或做错了什么有任何想法?

【问题讨论】:

【参考方案1】:

我认为你必须在你的后台进程中创建你的 backgroundContext。

并且需要监听backgroundContext发送的通知:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:self.backgroundContext];

在我的例子中,runupdate 在后台进程中运行:

- (void) runUpdate 
    NSManagedObjectContext *managedContext = [[NSManagedObjectContext alloc] init];
    managedContext.persistentStoreCoordinator = ...;
    [updateController registerBackgroundMoc:managedContext];
    //do all update stuff
    NSError *error;
    if (![managedContext save: &error] 
       ...
    
    [updateController unregisterBackgroundMoc:managedContext];

在我的 updateController 中,我执行了以下操作:

- (void) registerBackgroundMoc: (NSManagedObjectContext *) updateMoc 
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(mergeChanges:) name: NSManagedObjectContextDidSaveNotification object: updateMoc];


- (void) unregisterBackgroundMoc: (NSManagedObjectContext *) updateMoc 
    [[NSNotificationCenter defaultCenter] removeObserver: self name: NSManagedObjectContextDidSaveNotification object: updateMoc];

【讨论】:

以上是关于需要帮助设置后台托管对象上下文。在 FRC controllerDidChangeContent 上获取异常的主要内容,如果未能解决你的问题,请参考以下文章

Core Data 3 托管对象上下文

托管对象上下文未保存到持久存储

在多线程上下文中,在托管对象上设置属性时,CoreData 阻塞

在后台和主线程中使用托管对象上下文

在后台线程中更新托管对象上下文

在后台队列中保存临时托管对象上下文