2009-07-25 100 views
7

我正在修改一些现有的笨拙代码,只需简单地调用[tableView reloadData]就可以对任何更改使用更具体的表格更新与插入/删除方法。UITableView insertSections:withRowAnimation:导致请求所有表格单元格

但是,我得到这样做有一些非常糟糕的行为。以前,正如人们所想象的那样,当表格加载时,它只会请求单元格用于当时可见的行。这是使用reloadData时的行为。

现在insertSections被调用,全部该更新后,请求单元格,可能是数百。这会导致为每一行创建单元格,从而彻底破坏可重用的单元队列,并造成浪费。我必须做错了什么。

的变化是这样的简单,代码导致的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]; 
} 

我可以切换回:那导致的tableView要求一切

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context { 
    // ... ensure it's the right key 
    [tableView reloadData]; 
} 

代码并且看到行为改变。令人沮丧。想法?


添加赏金只是为了看看有没有人有更多的见解。

的beginUpdates/endUpdates不会影响任何东西,我不希望它来,这只是一个命令,没有什么额外的凝聚成一个单一的更新。

我想这仅仅是希望动画的副作用。为了让所有内容“滑动”,它必须呈现一切。游戏结束。

+0

你是怎么确定所有的单元格一次都被请求的?没有人出列? – Pascal 2009-10-27 15:15:10

+0

我创建了一个小型测试项目,可以重现您正在观察的行为。它真的很好奇。如果您指定了UITableViewRowAnimationNone,则行为是相同的,因此不能仅仅是动画。 如果insertSections:withRowAnimation:被调用时插入位置不在屏幕上,则不会发生此问题。 – 2009-10-27 22:15:52

回答

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]; 
+0

那么,在一点额外的信息可能是有用的,这是一个完全空表最初。为了保持用户界面的响应,我推迟了加载数据的方式,所以它最初会出现空白,并且会在它们进入网络时添加这些部分。因此,从没有节到使用reloadData的所有节都可以正常工作,但是显式添加节导致混乱?奇怪的。 – 2009-07-25 18:13:25

+0

不,这是预期的,为什么你需要beginUpdates/endUpdates调用来包装你正在做的事情。如果没有这些,tableView必须假设每次修改后都会影响显示,这意味着它必须查询所有部分以计算可见的单元格,然后获取所有可见的单元格。当您执行beginUpdates时,tableView将停止更新,直到您调用endUpdates,此时它可以一次性查询所有中间状态。 “ – 2009-07-25 23:01:07

+0

”而不询问您的中介国家,“我需要更多咖啡 – 2009-07-25 23:02:49