NSFetchedResultsController:在后台线程中提取 [英] NSFetchedResultsController: Fetch in a background thread
问题描述
我有一个或多或少的基本 UITableViewController
与 NSFetchedResultsController
。 UITableViewController
被推送到 navigationController的
堆栈。但是推送动画不顺利,因为 NSFetchedResultsController
的提取在主线程上执行,因此阻止了UI。
I have a more or less basic UITableViewController
with a NSFetchedResultsController
. The UITableViewController
is pushed onto the navigationController's
stack. But the push animation isn't smooth because the fetch of NSFetchedResultsController
is performed on the main thread, and therefore blocks the UI.
我的问题是:如何在后台线程中执行 NSFetchedResultsController
的抓取以保持动画平滑?
My question is: How can I perform the fetch of the NSFetchedResultsController
in a background thread to keep the animation smooth?
NSFetchedResultsController
和委托方法如下所示:
The NSFetchedResultsController
and the delegate methods look like this:
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"GPGrade" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
//Set predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"parent == %@", self.subject];
[fetchRequest setPredicate:predicate];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = @[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"SubjectMaster"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _fetchedResultsController;
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];
break;
case NSFetchedResultsChangeUpdate:
//[self configureCell:(GPSubjectOverviewListCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}
推荐答案
是每个线程一个管理对象上下文,每个MOC一个线程。考虑到这一点,您需要在主线程上执行Fetchched Results Controller的获取,因为这是将与FRC的托管对象交互的线程。 (请参见核心数据编程指南 - 核心数据的并发性)
The general rule with Core Data is one Managed Object Context per thread, and one thread per MOC. With that in mind you need to perform the fetch for the Fetched Results Controller on the main thread, as this is the thread that will be interacting with the FRC's Managed Objects. (See Core Data Programming Guide - Concurrency with Core Data)
如果您在动画中遇到性能问题,您应该考虑一些方法来确保抓取在视图被推送之前或之后执行。通常,您将在视图控制器的 viewDidLoad:
中执行提取,导航控制器不会推送视图,直到提取完成。
If you are having performance issues with the animation you should probably look at ways to ensure that the fetch is performed before or after the view is pushed. Normally you would perform the fetch in the view controller's viewDidLoad:
, and the navigation controller wouldn't push the view until the fetch was complete.
这篇关于NSFetchedResultsController:在后台线程中提取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!