【问题标题】:What is the benefit of calling beginUpdates/endUpdates for a UITableView as opposed to not doing so?与不这样做相比,为 UITableView 调用 beginUpdates/endUpdates 有什么好处?
【发布时间】:2014-04-24 05:07:56
【问题描述】:

我有一个数组数组,用于表视图的数据源。有一次,我可能不得不对这个数据结构做一些复杂的修改。 (例如,我可能需要做的一系列操作是:这里删除一行,那里插入一行,这里插入一个节,删除另一行,插入另一行,删除另一行,插入另一个节——你得到想法。)如果对于序列中的每个操作,我只是更新数据源,然后立即对表视图进行相应的更新,这很容易做到。换句话说,伪代码将如下所示:

[arrayOfArrays updateForOperation1];
[tableView updateForOperation1];

[arrayOfArrays updateForOperation2];
[tableView updateForOperation2];

[arrayOfArrays updateForOperation3];
[tableView updateForOperation3];

[arrayOfArrays updateForOperation4];
[tableView updateForOperation4];

// Etc.

但是,如果我将这些操作包含在 beginUpdates/endUpdates “块”中,则此代码将不再起作用。要了解原因,从空表视图开始成像,并在第一部分的开头依次插入四行。这是伪代码:

[tableView beginUpdates];

[arrayOfArrays insertRowAtIndex:0];
[tableView insertRowAtIndexPath:[row 0, section 0]];

[arrayOfArrays insertRowAtIndex:0];
[tableView insertRowAtIndexPath:[row 0, section 0]];

[arrayOfArrays insertRowAtIndex:0];
[tableView insertRowAtIndexPath:[row 0, section 0]];

[arrayOfArrays insertRowAtIndex:0];
[tableView insertRowAtIndexPath:[row 0, section 0]];

[tableView endUpdates];

当 endUpdates 被调用时,表格视图发现您插入的四行都在第 0 行发生冲突!

如果我们真的想保留代码的 beginUpdates/endUpdates 部分,我们必须做一些复杂的事情。 (1) 我们在不更新表格视图的情况下对数据源进行所有更新。 (2) 我们弄清楚所有更新之前的数据源部分如何映射到所有更新之后的数据源部分,以找出我们需要对表视图执行哪些更新。 (3) 最后,更新表格视图。伪代码看起来像这样来完成我们在上一个示例中尝试做的事情:

oldArrayOfArrays = [self recordStateOfArrayOfArrays];

// Step 1:
[arrayOfArrays insertRowAtIndex:0];
[arrayOfArrays insertRowAtIndex:0];
[arrayOfArrays insertRowAtIndex:0];
[arrayOfArrays insertRowAtIndex:0];

// Step 2:
// Comparing the old and new version of arrayOfArrays,
// we find we need to insert these index paths:
// @[[row 0, section 0],
//   [row 1, section 0],
//   [row 2, section 0],
//   [row 3, section 0]];
indexPathsToInsert = [self compareOldAndNewArrayOfArraysToGetIndexPathsToInsert];

// Step 3:

[tableView beginUpdates];

for (indexPath in indexPathsToInsert) {
    [tableView insertIndexPath:indexPath];
}

[tableView endUpdates];

为什么要为 beginUpdates/endUpdates 做这一切?文档说使用 beginUpdatesendUpdates 来做两件事:

  1. 动画一堆插入、删除和其他操作同时
  2. “如果您不在此块内进行插入、删除和选择调用,则行数等表属性可能会变得无效。” (这到底是什么意思?)

但是,如果我不使用 beginUpdates/endUpdates,表格视图看起来会同时为各种更改设置动画,并且我认为表格视图的内部一致性不会被破坏。那么使用 beginUpdates/endUpdates 执行复杂方法有什么好处?

【问题讨论】:

  • Table View Programming Guide for iOS 非常清楚地涵盖了这一点。请参阅Batch Insertion, Deletion, and Reloading 部分
  • @rmaddy 所以我看到 beginUpdates/endUpdates 定义了一个动画块(以及一组插入/删除,以便所有删除发生在所有插入之前)。在我的情况下,我应该做的似乎是做我在我的问题的第一个伪代码列表中概述的事情(即,不使用 beginUpdates/endUpdates)。但是,我担心的是每次插入/删除都像自己对 [UIView animationWithDuration:...] 的调用,因此下一次调用将取消在上一次调用中排序的动画。或者 UITableView 是否足够智能,可以在一个动画块中为插入/删除设置动画?
  • 我也遇到了同样的问题,但这个问题还没有真正得到解答...所以你最终没有调用 beginUpdates/endUpdates 吗?它似乎在我的应用程序中运行良好,但我担心我错过了一些东西。附带说明一下,NSTableView 没有这个“问题”,插入和删除的顺序很重要。

标签: ios objective-c uitableview


【解决方案1】:

每次添加/删除表格项时,都会调用 tableView:numberOfRowsInSection: 方法 - 除非您将这些调用用 begin/endUpdate 包围。如果您的数组和表格视图项不同步,则如果没有开始/结束调用,则会引发异常。

【讨论】:

  • 听起来 begin/endUpdates 是用来告诉表视图在调用 endUpdates 之前推迟执行更新,以便在订购插入/删除时可以参考正确的索引。但是除了帮助您保持数据源和表视图同步之外,是否有必要将插入和删除分组到一个动画块中?即,如果省略 begin/endUpdates,是否会出现问题,即每个插入/删除就像它自己的动画块一样,取消在前一个插入/删除中排序的动画? (在我的问题的 cmets 中查看我对 @rmaddy 的评论)
猜你喜欢
  • 1970-01-01
  • 2016-03-19
  • 1970-01-01
  • 2012-05-19
  • 1970-01-01
  • 1970-01-01
  • 2021-10-07
  • 1970-01-01
  • 2013-08-18
相关资源
最近更新 更多