UITableView insertSections: withRowAnimation: 导致请求所有表格单元格
Posted
技术标签:
【中文标题】UITableView insertSections: withRowAnimation: 导致请求所有表格单元格【英文标题】:UITableView insertSections: withRowAnimation: causing all table cells to be requested 【发布时间】:2009-07-25 04:32:29 【问题描述】:我正在修改一些现有的笨拙的代码,这些代码只是在任何更改上调用[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 不会影响任何东西,我不希望它影响,这只是一个命令,没有什么额外的东西可以合并成一个更新。
我认为这只是渴望动画的副作用。为了让所有东西都“滑入”,它必须有所有东西来渲染。游戏结束。
【问题讨论】:
您是如何确定所有单元格都被同时请求的?没有人出队吗? 我创建了一个小型测试项目,可以重现您观察到的行为。它真的很好奇。不能单独作为动画,因为如果您指定 UITableViewRowAnimationNone,行为是相同的。如果调用 insertSections:withRowAnimation: 时插入位置不在屏幕上,则不会出现此问题。 【参考方案1】:您似乎是在告诉表格插入所有部分,这基本上相当于重新加载。当您告诉表格它需要加载一个部分时,它需要读取该部分中的所有项目。此外,您是在 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];
【讨论】:
好吧,一点额外的信息可能会有用,这最初是一个完全空的表。我推迟了数据的加载以保持 UI 响应,所以它最初是空白的,并在它们离开网络时添加这些部分。因此,使用 reloadData 从没有部分到所有部分都可以正常工作,但是显式添加部分会导致混乱?很奇怪。 不,这是预期的,以及为什么需要 beginUpdates/endUpdates 调用来包装您正在做的事情。如果没有这些,tableView 必须假设在您所做的每次修改后都可能会影响显示,这意味着它必须查询所有部分以计算哪些单元格是可见的,然后获取所有可见的单元格。当您执行 beginUpdates 时,tableView 会停止更新,直到您调用 endUpdates,此时它可以通过查询所有中间状态来一次性完成所有操作。 “不询问你的中间状态,”我需要更多的咖啡以上是关于UITableView insertSections: withRowAnimation: 导致请求所有表格单元格的主要内容,如果未能解决你的问题,请参考以下文章
UITableView insertSections: withRowAnimation: 导致请求所有表格单元格
UICollectionView insertSections 错误 - NSInvalidArgumentException 原因 setObjectForKey 对象不能为 nil UIColle