I have an operation in my app which requires a large, sometimes several second update with Core Data. Because I’d like to do more than just show a spinner, I’d like to display a progress bar to the end user. This presents some issues, however, because of Core Data’s insistence on running on the main thread. I have attempted to put Core Data on a background thread with dispatch_async with disastrous results. The problem is that UIKit also wants to run on the main thread and worse still, only does its updates after the current thread has ended. This results in the progress bar only being updated until after it has finished all its processing!
How can get the UI updated and safely update my data?
NSArray* items = [[response.data objectForKey:@"result"] objectForKey:@"items"];
NSManagedObjectContext* context = [RBGameItemController sharedInstance].managedObjectContext;
int itemCount = [items count];
for (int i = 0; i < itemCount; i++) {
float progress = ((float)i/(float)itemCount)*0.95f;
self.progressView.progress = 0.5f + progress;
id item = [items objectAtIndex:i];
[GameItem gameItemFromDictionary:item inManagedObjectContext:context];
}
NSError* error = nil;
[context save:&error];
Core Data does not require working on the main thread, only that you have an NSManagedObjectContext for each separate thread. Create a new NSManagedObjectContext with the same backing store on a separate thread (using NSOperationQueue) and do the processing there. Once you save the NSManagedObjectContext from your alternate thread, your main thread’s context will pick up the changes from the backing store. To update your UI from the alternate thread, use
which is a method on NSObject. Good luck and comment if anything’s not clear.