我正在修改一些现有的严厉代码,只要在任何更改时调用[tableView reloadData]
,就可以使用插入/删除方法使用更具体的表更新。
但是,我这样做会有一些非常糟糕的行为。以前,正如人们所想象的那样,当表加载时,它只请求当时可见的行的单元格。这是使用reloadData
时的行为。
现在正在调用insertSections
,在更新后请求所有单元格,可以是数百个。这导致为每一行创建单元格,完全破坏可重用的单元格队列,并且只是浪费。我必须做错事。
更改就是这个简单的代码,导致tableView只询问可见的行:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
// ... ensure it's the right key
[tableView reloadData];
}
导致tableView要求所有内容的代码:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
// ... ensure it's the right key
NSUInteger sectionCount = [self sectionCount];
NSIndexSet *indices = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)];
[tableView insertSections:indices withRowAnimation:UITableViewRowAnimationFade];
}
我可以来回切换以查看行为的变化。令人沮丧。想法?
添加赏金只是为了看看是否有人有更多的洞察力。
beginUpdates / endUpdates不影响任何东西,我不指望它,这只是一个命令,没有什么额外的东西可以合并到一个更新中。
我认为这只是想要动画的副作用。要让所有内容“滑动”,它必须拥有一切要呈现的内容。游戏结束。
答案 0 :(得分:6)
看来你正在告诉表插入所有部分,这基本上等同于重新加载。当你告诉表它需要加载一个部分时,它需要读取该部分中的所有项目。此外,您在beginUpdates / endUpdates块之外执行此操作,这意味着每次添加该部分时,表都必须立即提交更改。如果将所有内容都包装在beginUpdates / endUpdates中,它将暂停所有查询,直到完成为止,这将允许系统合并冗余查询并消除不必要的查询。
您应该只使用添加的新部分调用insertSections。如果你这样做,那么tableview不必查询所有未改变的部分的信息,即使它们四处移动。此外,如果某个部分内的元素发生更改但该部分本身没有更改,则应使用该方法的行版本来修改该部分内的特定行,并且只会查询这些行。
下面是一个示例(来自基于CoreData的应用程序),它应该是重点。由于您有自定义模型而不是NSFetchedResultsController,因此您必须弄清楚正在进行的操作类型,而不仅仅是检查系统传递给您的一堆常量。
//Calculate what needs to be changed
[self.tableView beginUpdates];
for (i = 0 i < changeCount; i++) {
type = changes[i];
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:(id)[tableView cellForRowAtIndexPath:indexPath]
atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
[self.tableView endUpdates];