问题
I have setup a Core Data app with the usual boilerplate code, and the RootViewController initializes the FRC by calling this:
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil)
{
return __fetchedResultsController;
}
// configure the fetchRequest, sectionKey and cacheName
__fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest: fetchRequest
managedObjectContext: self.managedObjectContext
sectionNameKeyPath: sectionKey
cacheName: cacheName];
return __fetchedResultsController;
}
All the sample code I've seen does this. However, I have a large data set and with over 15,000 entries, it takes about 5 seconds to launch the app on the iPhone 4S. This is with caching enabled (without it, it takes 11 seconds), and with indexed attributes.
So I want to be able to show a UIActivityIndicatorView
which the app is waiting for this to load. I know how to generally load core data objects in the background thread and then merge them back into the main thread, but how can I initialize the FRC in the background thread so that all the objects are loaded and sectioned in the background?
I know I can load all the objects and partition them in a background thread into a custom dictionary and use that to present the data, but I would rather use the standard FRC calls and delegates.
Thanks.
回答1:
I'm not pretty sure what do you mean with using the NSFetchedResultsController
in the background, but based on my experience you could just simply set batch size for your fetch request like the following:
[fetchRequest setFetchBatchSize:20];
In this manner, during startup are loaded the first 20 elements, when you scroll the next 20 and so on. In addition, you could just select the properties to fetch with - (void)setPropertiesToFetch:(NSArray *)values
.
Another way is to have a (background) task that starts to fetch objects in background. I think that when fetched in background, the objects are cached in some way (but I'm not pretty sure) and so, you can access them from the main thread more rapidly.
Hope it helps.
回答2:
I think I've figured it out... you CAN create the FRC in the background thread and do the fetch in the main thread:
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil)
{
return __fetchedResultsController;
}
// create something to pass back to the first time FRC is initialized without fetching
__block NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
aFetchedResultsController.delegate = self;
[self.list_spinner startAnimating];
dispatch_async(self.filterMainQueue, ^{
NSFetchedResultsController *newFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest: fetchRequest
managedObjectContext: self.managedObjectContext
sectionNameKeyPath: sectionKey
cacheName: cacheName];
dispatch_async(dispatch_get_main_queue(), ^{
// stop the spinner here
[self.list_spinner stopAnimating];
NSError *error = nil;
if (![newFetchedResultsController performFetch:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
[SimpleListAppDelegate showCoreDataError: @"SimpleListViewController - FRC"];
}
__fetchedResultsController = nil;
newFetchedResultsController.delegate = self;
__fetchedResultsController = newFetchedResultsController;
[self.tableView reloadData];
});
});
return aFetchedResultsController;
}
来源:https://stackoverflow.com/questions/10908592/configure-nsfetchedresultscontroller-in-background-when-launching-core-data-app