Jeef
Jeef

Reputation: 27275

Background Loading Core Data

So I've been reading stack for a while and I realize I need to make a background core data NSManagedObjectContext as I'm loading a significant number of records and I want to not lock up the UI.

What I did was the following:

backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

NSPersistentStoreCoordinator *store = [[self managedObjectContext] persistentStoreCoordinator];

[backgroundContext setPersistentStoreCoordinator:store];

and in my function call I directly do:

 self.flightsFRC = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                    managedObjectContext:backgroundContext
                                    sectionNameKeyPath:nil
                                    cacheName:@"FlightRecords"];

My code is currently working but I feel like its "bad" else where I"m directly accessing the FRC without dealing with any synchronization or anything such as here where I iterate through the Fetched Results Controller.

FlightRecording *rec = [[[self flightsFRC] fetchedObjects] objectAtIndex:i];

Am I missing something? Should I be somehow loading records via a NSManagedObjectID this seems "too easy"

Upvotes: 0

Views: 104

Answers (1)

Wayne Hartman
Wayne Hartman

Reputation: 18477

You currently have your FRC pointing to the background context. Don't do that. Only point to a context on the main thread.

In order for your FRC to get notified of the changes, you actually need to merge the background context to your main thread context. Your CoreData stack object needs to register for notifications when the background context saves:

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

Since the notification can be posted from other threads, we'll need to do a check when this triggers to make sure we are on the main thread. If we're already there, then we can call the mergeChangesFromContextDidSaveNotification API on NSManagedObjectContext.

- (void)contextDidSave:(NSNotification *)notification {
    if (![NSThread isMainThread]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self contextDidSave:notification];
        });
    } else {
        [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
    }
}

Since your FRC is listening for changes when the data on main context changes, the FRC will then trigger its callbacks so that you can insert/delete/modify records in your tableview or collectionview.

EDIT:

It sounds like you may not be doing any changes on a background thread because you are not using the background context's performBlock: or a private queue to do the work:

[backgroundContext performBlock:^{
    // Do your work

    NSError *error = nil;
    BOOL success = [backgroundContext save:&error];

    //  error handling
}];

Upvotes: 1

Related Questions