为UITableView调用beginUpdates/endUpdates有什么好处,而不是这样做?

use*_*004 18 objective-c uitableview ios

我有一个数组数组,我正用于表视图的数据源.在一个时间实例中,我可能不得不对此数据结构进行一些复杂的修改.(例如,我可能需要做的一系列操作是:在这里删除一行,在那里插入一行,在此处插入一个部分,删除另一行,插入另一行,删除另一行,插入另一部分 - 你得到如果对于序列中的每个操作,我只更新数据源,然后立即对表视图执行相应的更新,这很容易做到.换句话说,伪代码看起来像:

[arrayOfArrays updateForOperation1];
[tableView updateForOperation1];

[arrayOfArrays updateForOperation2];
[tableView updateForOperation2];

[arrayOfArrays updateForOperation3];
[tableView updateForOperation3];

[arrayOfArrays updateForOperation4];
[tableView updateForOperation4];

// Etc.
Run Code Online (Sandbox Code Playgroud)

但是,如果我在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];
Run Code Online (Sandbox Code Playgroud)

当调用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];
Run Code Online (Sandbox Code Playgroud)

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

  1. 动画一堆插入,删除等操作同时进行
  2. "如果您不在此块中进行插入,删除和选择调用,则行计数等表属性可能会变为无效." (这究竟是什么意思呢?)

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

mde*_*eus 16

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

  • 听起来像begin/endUpdates是告诉表视图阻止执行更新,直到调用endUpdates,以便在订购插入/删除时可以引用正确的索引.但除了帮助您保持数据源和表视图同步之外,是否有必要将插入和删除分组到一个动画块中?即,如果省略begin/endUpdates,是否会出现问题,其中每个插入/删除就像它自己的动画块一样,取消了之前插入/删除中订购的动画?(在我的问题的评论中查看我对@rmaddy的评论) (5认同)