问题
I have several table views that send JSON requests to a server, store the results in core data, and display them using an NSFetchedResultsController. I was experimenting with GCD as follows:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// Perform JSON requests.
dispatch_async(dispatch_get_main_queue(), ^{
[theTableView reloadData];
});
});
However, this would cause some weird things to happen in the UI. New managed objects would render blank cells, deleted managed objects would cause cells to overlap, etc.
However, I found that if I did this, everything would render correctly.:
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
dispatch_async(dispatch_get_main_queue(), ^{
[theTableView endUpdates];
});
}
What I wanted to know is, why is this necessary? Since it fires as a result of [theTableView reloadData], why isn't it automatically included in the main queue? I thought maybe that it was because I didn't call it explicitly. In that case, do I have to wrap all my functions similarly?
回答1:
I assume that you use the main NSManagedObjectContext from a separate thread, which
is not allowed. For a background import, you have to create a separate managed object context,
import the objects in that context, and then save/merge the changes to the main context.
One possibility is to use a child context of the main managed object context:
NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc]
initWithConcurrencyType:NSPrivateQueueConcurrencyType];
childContext.parentContext = mainManagedObjectContext;
[childContext performBlock:^{
// Perform JSON requests.
// Save objects to childContext.
NSError *error;
BOOL success = [childContext save:&error];
}];
A context of the "private concurrency type" creates its own queue/thread, so that the performBlock is executed
in the background (and you need/must not create a queue yourself).
Saving childContext merges the changes up to the parent mainManagedObjectContext.
This should be sufficent for the fetched results controller to get notified of the
changes, and update the table view.
See Core Data Release Notes for OS X v10.7 and iOS 5.0 for more information about managed object context concurrency, and nested contexts.
回答2:
was
[theTableView beginUpdates]
written anywhere in the code? Try removing it. I suspect the UI weird stuff is happening because beginUpdates is already asynchronous itself (not blocking the main thread) for funky UITableView animations to take place.
来源:https://stackoverflow.com/questions/19271001/uitableview-endupdates-not-being-called-in-dispatch-async