AlexR
AlexR

Reputation: 5634

NSFetchedResultsController does not update TableView after UIManagedDocuments gets new data

I am using a NSFetchedResultsController in combination with a UIManagedDocument which gets updated in an background thread.

I have set up the NSFetchedResultsController exactly as described in this tutorial: How To Use NSFetchedResultsController

I have set the delegate _fetchedResultsController.delegate = self and the protocol for my view controller to NSFetchedResultsControllerDelegate.

My code works fine when it loads the data after launch. However, the NSFetchedResultsController does not update the TableView whenever it has processed and saved the data in the background thread. In particular, the NSFetchedResultsController's delegate methods -controllerWillChangeContent:controlleretc. are never being called.

I have double-checked that the SQLite database contains the data correctly. This is how I process and save the data in the view controller:

[backgroundContext performBlock:^{
        [company parseAttributesFrom:xmlStr inManagedObjectContext:backgroundContext]; //self.managedDocument.managedObjectContext

        NSError *error = nil;
        [backgroundContext save:&error];
         if (error) NSLog(@"error: %@",error.localizedDescription);
        [self.managedDocument.managedObjectContext performBlock:^{
            NSError *error = nil;
            [self.managedDocument.managedObjectContext save:&error];
            if (error) NSLog(@"error: %@",error.localizedDescription);
        }];
        [self.managedDocument saveToURL:self.managedDocument.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];
        [self.managedDocument updateChangeCount:UIDocumentChangeDone];
    }];

How can I get the NSFetchedResultsController to update the TableView automatically when the underlying data changes?

Thank you for your help!

Upvotes: 1

Views: 3275

Answers (2)

Jody Hagins
Jody Hagins

Reputation: 28409

I would suggest, when using UIManagedDocument, that you make your background context a child of the main context.

backgroundContext = [[NSManagedContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
backgroundContext.parent = self.managedDocument.managedObjectContext;

Now, you can do what you want in the background context, and when you want to save the background context, the changes will be stuffed into the main context. Of course, you will still need to save the UIManagedDocument, but that is done "seamlessly" in the background again, via setting the ChangeDone count.

[backgroundContext performBlock:^{
    [company parseAttributesFrom:xmlStr inManagedObjectContext:backgroundContext]; //self.managedDocument.managedObjectContext

    NSError *error = nil;
    [backgroundContext save:&error];
     if (error) NSLog(@"error: %@",error.localizedDescription);

    // NOTE: Now, the changes have been pushed into the main context of your document.
    // DO NOT call save directly on the managed document context.
    [self.managedDocument.managedObjectContext performBlock:^{
        [self.managedDocument updateChangeCount:UIDocumentChangeDone];
    }];
}];

Now, your background context just goes away, your main context sees the changes, and the document is saved.

Upvotes: 1

Nikita Pestrov
Nikita Pestrov

Reputation: 5966

I think that reason is in managedObjectContext. You make changes in background, and NSFetchedResultsController fetches from the main one. So you need to merge changes to that one context by adding an observer of changes in context

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:nil];

Here is a great tutorial by Marcus Zarra - The Guru of Core Data) Hope that helps. http://www.cimgf.com/2011/08/22/importing-and-displaying-large-data-sets-in-core-data/

Upvotes: 2

Related Questions