我正在UITableView上进行非常复杂的更新。可以同时移动多行、删除、插入和更改。在同一个tableView.beginUpdates()
/tableView.endUpdates()
块中处理这些更改的正确方法是什么?
示例:
Data before update ==> Data after update
================== =================
0: zero 0: zero
1: one 1: 555 (updated element five)
2: two 2: three
3: three 3: 222 (updated element two)
4: four
5: five
==> Elements 1 and 4 are deleted
==> Elements 2 and 5 are updated (content changes) and they switch their position
这可以使用一个简单的ViewController:来完成
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet var tableView: UITableView!
@IBOutlet var button: UIButton!
var rowTitles = ["zero", "one", "two", "three", "four", "five"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rowTitles.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = rowTitles[indexPath.row]
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
@IBAction func click() {
tableView.beginUpdates()
// "zero", "one", "555", "three", "four", "222"
rowTitles[2] = "555"
rowTitles[5] = "222"
// "zero", "555", "three", "four", "222"
rowTitles.remove(at: 1)
// "zero", "555", "three", "222"
rowTitles.remove(at: 3)
// Delete "one" (original index = 1)
tableView.deleteRows(at: [IndexPath(row: 1, section: 0)], with: .automatic)
// Delete "four" (original index = 4)
tableView.deleteRows(at: [IndexPath(row: 4, section: 0)], with: .automatic)
// Move "two" and "five", use new old index for source and new index for destination
tableView.moveRow(at: IndexPath(row: 2, section: 0), to: IndexPath(row: 3, section: 0))
tableView.moveRow(at: IndexPath(row: 5, section: 0), to: IndexPath(row: 1, section: 0))
// CRASH
//tableView.reloadRows(at: [IndexPath(row: 5, section: 0)], with: .automatic)
tableView.endUpdates()
}
}
除了同时移动和重新加载第2行和第5行之外,一切都很好。如果未使用IreloadRows(...)
,则代码会运行,但会生成一个列表zero, five, three, two
。因此,元素的顺序正确,但行尚未更新为555
和222
。
当将reloadRows(...)
与原始索引2和5一起使用时,应用程序崩溃,因为对相同的索引调用了move+delete(似乎在内部将重载处理为delete+add(。
在endUpdates()
之后使用reloadRows(...)
可以提供正确的结果。然而,我想知道这是否是正确的做法。关于Apple文档,应在beginUpdates ... endUpdates
中调用reloadRows(...)
。
那么,解决这个问题的正确方法是什么
不完全确定你想要什么视觉效果,但。。。
您可能需要重新加载表视图并,然后删除/重新排列行。
这样试试:
@IBAction func click() {
rowTitles[5] = "555"
rowTitles[2] = "222"
let p1 = IndexPath(row: 2, section: 0)
let p2 = IndexPath(row: 5, section: 0)
self.tableView.reloadRows(at: [p1, p2], with: .automatic)
rowTitles.remove(at: 1)
rowTitles.remove(at: 3)
// need to update order in array
rowTitles[1] = "555"
rowTitles[3] = "222"
tableView.performBatchUpdates({
// Delete "one" (original index = 1)
tableView.deleteRows(at: [IndexPath(row: 1, section: 0)], with: .automatic)
// Delete "four" (original index = 4)
tableView.deleteRows(at: [IndexPath(row: 4, section: 0)], with: .automatic)
// Move "two" and "five", use new old index for source and new index for destination
tableView.moveRow(at: IndexPath(row: 2, section: 0), to: IndexPath(row: 3, section: 0))
tableView.moveRow(at: IndexPath(row: 5, section: 0), to: IndexPath(row: 1, section: 0))
}, completion: { _ in
// if you want to do something on completion...
})
}
最终结果顺序为:
zero
555
three
222