ios - 如何在相同的 beginUpdates / endUpdates 操作中移动和重新加载 UITableView 行?
问题描述
我正在对 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(...)
未使用,代码运行但结果为 list zero, five, three, two
。因此,元素的顺序正确,但行尚未更新为555
和222
。
当reloadRows(...)
与原始索引 2 和 5 一起使用时,应用程序崩溃,因为已为相同的索引调用 move+delete(似乎重新加载在内部处理为 delete+add)。
使用reloadRows(...)
AFTERendUpdates()
可以提供正确的结果。但是,我想知道这是否是正确的方法。关于 Apple DocsreloadRows(...)
应该在beginUpdates ... endUpdates
.
那么,解决这个问题的正确方法是什么?
解决方案
不完全确定你想要什么样的视觉效果,但是......
您可能想要重新加载表格视图,然后删除/重新排列行。
试试这样:
@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
推荐阅读
- javascript - 如何在没有任何性能问题的情况下渲染 Timer
- laravel - Laravel 测试迁移污染断言
- excel - 如何通过 Excel Power Query 访问 Clockify API
- c# - C# - 在内存中生成数据库备份脚本
- python - Python 通用数据引擎
- java - 如何在java中进行相互SSL身份验证
- ios - 如何在 Swift 中实现填空
- c# - 如何使用 C# 和 SQL Server 编写代码以从多个表中获取数据
- mongodb - 在 WSO2 EI 中使用 MongoDB
- google-cloud-iot - 为 Google IOT 运行源运行网关时出错