我使用CoreData基于Xcode Master / Detail模板UITableView
。当NSManagedObject
中的detailViewController
的属性发生变化时,对来电的调用
[self.tableView endUpdates]
需要一秒钟以上。该表有大约30个条目。
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
NSLog(@"endUpdates start");
[self.tableView endUpdates];
NSLog(@"endUpdates end");
}
这是日志输出,类型4是NSFetchedResultsChangeUpdate
。只更新了一行。
2014-01-25 12:40:31.313 Batteries[1511:60b] beginUpdates
2014-01-25 12:40:31.315 Batteries[1511:60b] Type: 4
2014-01-25 12:40:31.317 Batteries[1511:60b] endUpdates start
2014-01-25 12:40:32.344 Batteries[1511:60b] endUpdates end
使用插入和删除,endUpdates
方法调用很快:
2014-01-25 12:39:46.732 Batteries[1511:60b] beginUpdates
2014-01-25 12:39:46.733 Batteries[1511:60b] Type: 2
2014-01-25 12:39:46.735 Batteries[1511:60b] endUpdates start
2014-01-25 12:39:46.742 Batteries[1511:60b] endUpdates end
如果我将beginUpdates - endUpdates
序列替换为[self.tableView reloadData]
,则会更快:
2014-01-25 13:02:32.028 Batteries[1522:60b] Type: 4
2014-01-25 13:02:32.032 Batteries[1522:60b] reload start
2014-01-25 13:02:32.034 Batteries[1522:60b] reload end
这里要求的是NSFetchedResultsController
代码:
#pragma mark - 获取结果控制器
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Battery" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
// sort by identifier ASC
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"identifier" ascending:YES];
NSArray *sortDescriptors = @[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Master"];
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
{
NSLog(@"beginUpdates");
[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;
NSLog(@"Type: %u", type);
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
self.insertedIndexPath = newIndexPath;
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
NSLog(@"endUpdates start");
[self.tableView endUpdates];
// [self.tableView reloadData];
NSLog(@"endUpdates end");
if (self.insertedIndexPath) {
[self.tableView scrollToRowAtIndexPath:self.insertedIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
self.insertedIndexPath = nil;
}
}
/*
// Implementing the above methods to update the table view in response to individual changes may have performance implications if a large number of changes are made simultaneously. If this proves to be an issue, you can instead just implement controllerDidChangeContent: which notifies the delegate that all section and object changes have been processed.
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
// In the simplest, most efficient, case, reload the table view.
[self.tableView reloadData];
}
*/
- (void)configureCell:(BatteryCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.identifierLabel.text = [object valueForKey:@"identifier"];
cell.manufacturerLabel.text = [[object valueForKey:@"manufacturedBy"] manufacturerName];
}
有没有人知道它为什么会这样?