insertRowsAtIndexPaths 为每一行调用 cellForRowAtIndexPath

发布于 2024-11-08 14:34:58 字数 588 浏览 0 评论 0原文

我正在尝试使用 insertRowsAtIndexPaths 将一堆行插入到空 UITableView 中。 (我知道这听起来没那么有用,但这是我真正需要做的事情的简化版本。)

我看到的问题是,在进行 insertRowsAtIndexPaths 调用后,我对每一行都进行了 cellForRowAtIndexPath 调用插入的,而不仅仅是那些可见的。

这似乎不对。如果这样做的话,对我来说几乎毫无用处。

我看到的唯一有点奇怪的其他工件是,当我这样做时,它实际上似乎将行动画到位。这不是 withRowAnimation,因为它设置为 none。但这里似乎存在某种更高级别的动画概念。我有一个奇怪的想法,当它将行动画到位时,它认为它需要更多/所有行的单元格,直到它们被推离屏幕。但如果不使用我希望避免的 reloadData ,我就无法关闭此动画。

一般来说,我有一个在幕后发生变化的数据集。我可以仔细检查并构建更改以生成插入/删除/重新加载调用的数据。但我不能将其限制为屏幕上的内容,因为它与数据提供者不匹配。

我想我一定错过了一些东西......有什么想法吗?

(我在 beginUpdates/endUpdates 对中执行此操作,但这似乎没有什么区别。)

I'm trying to insert a bunch of rows into an empty UITableView in one step using insertRowsAtIndexPaths. (I know that this doesn't sound all that useful, but it's a simplified version of what I really need to do.)

The issue I'm seeing is that after I make the insertRowsAtIndexPaths call, I get cellForRowAtIndexPath calls for every row I inserted, rather than just those that are visible.

That doesn't seem right. And it's pretty much useless to me if it does this.

The only slightly odd other artifact I see is that when I do this, it actually seems to animate the rows into place. This isn't the withRowAnimation, since that's set to none. But it seems there's some sort of higher level animation concept going on here. I had the off-idea that as it animated the rows into place it thought it needed cells for more/all the rows until they got pushed off screen. But I can't turn off this animation without just using reloadData which I'd prefer to avoid.

Generally I have a data set that changes behind the scenes. I can carefully go through and construct the changes to generate data for the insert/delete/reload calls. But I can't limit that to what's on screen since then it doesn't match the data provider.

I figure I must be missing something ... any ideas?

(I am doing this within a beginUpdates/endUpdates pair but that seems to make no difference.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

雄赳赳气昂昂 2024-11-15 14:34:58

我今天和一些苹果公司的人聊过。该问题肯定与插入新行时 UITableView 执行的动画有关。这是为单元格创建新行的动画,与通过 insertRowsAtIndexPaths 引入这些行时使用的动画分开。

由于表级动画通过某种“向下增长”的方式创建新行,因此在插入动画期间,少量的许多单元格被视为可见,并且表将为它们调用 cellForRowAtIndexPath。

似乎没有任何适用于所有情况的替代实现。对于我的情况,推荐的解决方案是“撒谎”:找出动画之后页面上将存在哪些单元格并插入它们。该动画完成后,插入不会显示的其余单元格,并且表格不会调用 cellForRowAtIndexPath。

这需要在表视图和“真实”数据源之间实现一个对象,该对象可以在动画持续时间内向表视图“谎报”表中的行数。很痛苦,但这显然是类似案例中所做的事情。

I talked to some Apple folks today. The issue is definitely related to the animation that UITableView does when you insert new rows. This is the animation that happens to create new rows for cells, separate from the animation that is used when those rows are brought in via insertRowsAtIndexPaths.

Since the table-level animation creates new rows through a sort of "grow down" kind of thing, during the insert animation small amounts of many cells are considered visible and the table will call cellForRowAtIndexPath for them.

There doesn't seem to be any alternative implementation for this that works for all cases. The recommended solution for my case is to "lie": figure out what cells will exist on page after the animation and insert those. After that animation completes, insert the remainder of cells that won't show and the table won't call cellForRowAtIndexPath.

This requires implementing an object between the table view and the "real" data source that can "lie" to the table view about the number of rows in the table for the duration of the animation. Painful, but that's apparently what has been done in similar cases.

み格子的夏天 2024-11-15 14:34:58

我遇到了同样的问题,我所做的就是声明一个名为 bMassiveLoad 的属性初始化为 false。
在执行“大量加载”之前,我将其设置为 true,并且在 cellForRowAtIndexPath 中做的第一件事是检查该属性。
在“maseive load”结束时,我再次将其设置为 false 并调用 reloadData...

我知道这不是一个漂亮的答案,但它对我有帮助。

I had the same problem, what I did was to declare an attribute called bMassiveLoad initialized to false.
Before I do the 'massive load' I set it to true and the first thing I do in the cellForRowAtIndexPath was to check for that attribute.
At the end of the 'maseive load' I set it to false again and call reloadData...

I know that it is not a beautiful answer, but it helps me.

旧竹 2024-11-15 14:34:58

我能够通过结合这里的一些答案来解决这个问题:

按照 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];
    }
}

I was able to solve this by combining a few answers from here:

set the massive load boolean as needed as suggested by 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;
        ...
    }
}

and reload the visible rows when it ends

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
    if (massiveLoad) {
        massiveLoad = NO;
        [self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationFade];
    }
}
对岸观火 2024-11-15 14:34:58

UITableView 在调用 insertRowsAtIndexPaths 后立即调用相关的委托和数据源方法,以获取单元格和可见单元格的其他内容。这与动画是否设置为“是”或“否”无关。

请参阅讨论 这里

如果您只想让 tableView 更新可见单元格,那么只需更新您的 dataSource 并调用 [tableView reloadData] 即可。

UITableView calls the relevant delegate and data source methods immediately after a call to insertRowsAtIndexPaths to get the cells and other content for visible cells. This is regardless of whether or not animated is set to YES or NO.

See the discussion here

If you only want the tableView to update the visible cells, then just update your dataSource and call [tableView reloadData].

花开柳相依 2024-11-15 14:34:58

我不知道您描述的行为是否正确,但是 UITableView 有两个方法:beginUpdatesendUpdates (此处)旨在优化重绘(以便动画仅在最后完成,否则它们将被一一完成,这可能会产生对 cellForRowAtIndexPath 的调用)。

现在,我不确定这是否可以帮助您,但也许您可以尝试一下......

I don't know whether the behavior you describe is correct, but UITableView has got two methods: beginUpdates and endUpdates (here) that are meant to optimize redrawing (so that animating is done only at the end, otherwise they are done one by one and this could possibly produce the call to cellForRowAtIndexPath).

Now, I am not sure if this could help you, but perhaps you can give this a try...

那伤。 2024-11-15 14:34:58

我觉得可能有一种不同的方法来解决这个问题,但我发现,如果您在可见范围内有现有的单元格(例如,如果您始终有 10 个可见单元格,并且您用 10 初始化 tableView空白单元格),当您添加新行时,不会在 cellForRowAtIndexPath 中调用额外的行。

那么,该怎么办呢。这就是我解决这个问题的方法。当我创建 tableView 时,我将单元格添加到可见区域。他们一片空白。然后,当我插入新行时,我只添加了额外行的索引路径(即,如果我有 10 个可见行并且想要添加 50 行,包括可见行,我只添加 40 行,因为前 10 行已经存在)。这当然会留下 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;
}

这应该可以满足您的需要,并且仅加载屏幕上显示的单元格

I feel like there may be a different way to go about this, but what I have found is that if you have existing cells in the visible range (for example, if you have 10 cells visible at all times and you initialize the tableView with 10 blank cells), when you add new rows, the extra rows are not called in cellForRowAtIndexPath.

So, what to do about it. This is how I went about fixing this. When I created the tableView, I added cells to the visible region. They were blank. Then, when I inserted new rows, I only added index paths for the extra rows (i.e. if I have 10 visible rows and want to add 50 rows, including the visible rows, I only added 40 since the first 10 already exist). This of course leaves you with 10 blank cells. At this point, you can use:

NSArray *indexPaths = [myTableView indexPathsForVisibleCells];
[myTableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];

This selects your 10 visible blank cells and reloads them with the new information you have passed in (I assume you load data into an array for this part). You will need to add a little logic to your cellForRowAtIndexPath method such as:

if (![myDataArray count]) {
    // create a blank cell;
} else {
    // add context to your cells as you want;
}

This should do the trick for you and only load the cells you have showing on the screen

九歌凝 2024-11-15 14:34:58

为了快速,你可以尝试这个

self.mainTableView.beginUpdates()
    self.mainTableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.Fade)
    self.mainTableView.reloadRowsAtIndexPaths(self.mainTableView.indexPathsForVisibleRows!, withRowAnimation: UITableViewRowAnimation.Fade)
    self.mainTableView.endUpdates()

For swift you can try this

self.mainTableView.beginUpdates()
    self.mainTableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.Fade)
    self.mainTableView.reloadRowsAtIndexPaths(self.mainTableView.indexPathsForVisibleRows!, withRowAnimation: UITableViewRowAnimation.Fade)
    self.mainTableView.endUpdates()
哀由 2024-11-15 14:34:58

UITableView将通过cellForRowAtIndexPath:方法请求可见单元格,当单元格较多(例如1k个单元格)时,它可以减少处理时间,并通过可重用单元格机制减少内存消耗。如果您需要处理所有单元格,那么您应该实现一个自定义方法来重新处理源数据,然后调用 [tableView reloadData] 来更新 UI。

The UITableView will request the visible cells by cellForRowAtIndexPath: method, and it can reduce the processing time when there are many cells, ex 1k cells, and reduce spent memory by reusable cell mechanism. If you need to process all cells, then you should implement a custom method to re-process your source data, and then call [tableView reloadData] to update the UI.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文