如何在相同的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(...),则代码会运行,但会生成一个列表zero, five, three, two。因此,元素的顺序正确,但行尚未更新为555222

当将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

最新更新