insertRowsAtIndexPaths为每一行调用cellForRowAtIndexPath

问题描述

|| 我正在尝试使用insertRowsAtIndexPaths将一大堆行插入到空的UITableView中。 (我知道这听起来并没有那么有用,但这是我真正需要做的简化版本。) 我看到的问题是,在我执行insertRowsAtIndexPaths调用之后,对于插入的每一行,我都会得到cellForRowAtIndexPath调用,而不仅仅是可见的行。 这似乎不正确。如果这样做,对我来说几乎没有用。 我看到的唯一一点奇怪的工件是,当我执行此操作时,它实际上似乎在将行设置为动画。这不是withRowAnimation,因为将其设置为none。但是似乎这里有某种更高层次的动画概念。我有一个不理想的想法,因为它使行充满活力,以为需要更多/所有行的单元格,直到它们被推离屏幕为止。但是我不能仅使用reloadData来关闭该动画,而我更希望避免这种情况。 通常,我有一个后台更改的数据集。我可以仔细检查并构造更改以生成用于插入/删除/重新加载调用的数据。但我不能将其限制为屏幕上显示内容,因为它与数据提供者不匹配。 我想我一定想念一些东西...有什么想法吗? (我在beginUpdates / endUpdates对中执行此操作,但这似乎没有什么区别。)     

解决方法

我今天和一些苹果公司的人聊天。这个问题肯定与插入新行时UITableView所做的动画有关。这是为单元格创建新行的动画,它与通过insertRowsAtIndexPaths引入这些行时使用的动画分开。 由于表级动画通过某种“向下增长”的方式创建新行,因此在插入动画期间,少量的许多单元格被视为可见,并且表将为其调用cellForRowAtIndexPath。 似乎没有适用于所有情况的替代方法。对于我的情况,推荐的解决方案是\“ lie \”:找出动画后页面上将存在哪些单元格并将其插入。该动画完成后,插入将不会显示的其余单元格,并且表格将不会调用cellForRowAtIndexPath。 这需要在表格视图和\“ real \”数据源之间实现一个对象,该对象可以\“躺在\”表格视图中,以了解动画期间表格中的行数。痛苦的,但这显然是在类似情况下所做的。     ,我遇到了同样的问题,我要做的是声明一个名为bMassiveLoad的属性,该属性已初始化为false。 在执行“大规模加载”之前,我将其设置为true,并且在cellForRowAtIndexPath中要做的第一件事是检查该属性。 在“巨大负载”的结尾,我再次将其设置为false并调用reloadData ... 我知道这不是一个很好的答案,但对我有帮助。     ,我可以通过合并以下几个答案来解决此问题: 根据pocjoc的建议根据需要设置大量负载布尔值
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    UITableView *tableView = self.tableView;
    switch(type) {
        case NSFetchedResultsChangeInsert:
            massiveLoad = YES;
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        ...
    }
}
并在结束时重新加载可见行
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
    if (massiveLoad) {
        massiveLoad = NO;
        [self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationFade];
    }
}
    ,在调用insertRowsAtIndexPaths以获取单元格和可见单元格的其他内容之后,UITableView会立即调用相关的委托和数据源方法。这与是否将动画设置为“是”或“否”无关。 看到这里的讨论 如果只希望tableView更新可见单元格,则只需更新dataSource并调用[tableView reloadData]。     ,我不知道您所描述的行为是否正确,但是
UITableView
有两种方法:
beginUpdates
endUpdates
(此处),它们用于优化重绘(因此动画只能在最后完成,否则,它们将一一完成) 1,这可能会产生对
cellForRowAtIndexPath
的调用)。 现在,我不确定这是否可以帮助您,但是也许您可以尝试一下...     ,我觉得可能有不同的解决方法,但是我发现,如果您在可见范围内有现有的单元格(例如,如果您始终有10个单元格可见,并且将tableView初始化为10空白单元格),当您添加新行时,多余的行在ѭ5中不会被调用。 因此,该怎么做。这就是我解决该问题的方法。创建tableView时,我将单元格添加到了可见区域。他们是空白。然后,当我插入新行时,我仅添加了额外行的索引路径(即,如果我有10条可见行,并且想添加50行(包括可见行),由于前10条已经存在,我只添加了40条)。当然,这会留下10个空白单元格。此时,您可以使用:
NSArray *indexPaths = [myTableView indexPathsForVisibleCells];
[myTableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
这将选择10个可见的空白单元格,并使用传入的新信息重新加载它们(我假设您将数据加载到此部分的数组中)。您将需要在
cellForRowAtIndexPath
方法中添加一些逻辑,例如:
if (![myDataArray count]) {
    // create a blank cell;
} else {
    // add context to your cells as you want;
}
这应该为您解决问题,并且仅加载屏幕上显示的单元格     ,为了迅速,您可以尝试一下
self.mainTableView.beginUpdates()
    self.mainTableView.insertRowsAtIndexPaths(indexPaths,withRowAnimation: UITableViewRowAnimation.Fade)
    self.mainTableView.reloadRowsAtIndexPaths(self.mainTableView.indexPathsForVisibleRows!,withRowAnimation: UITableViewRowAnimation.Fade)
    self.mainTableView.endUpdates()
    ,UITableView将通过“ 11”方法请求可见的单元格,并且可以减少存在多个单元格(例如1k单元格)时的处理时间,并通过可重复使用的单元格机制来减少已用内存。如果需要处理所有单元格,则应实现一个自定义方法来重新处理源数据,然后调用ѭ12来更新UI。