首页 > 解决方案 > 如何在相同的 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。因此,元素的顺序正确,但行尚未更新为555222

reloadRows(...)与原始索引 2 和 5 一起使用时,应用程序崩溃,因为已为相同的索引调用 move+delete(似乎重新加载在内部处理为 delete+add)。

使用reloadRows(...)AFTERendUpdates()可以提供正确的结果。但是,我想知道这是否是正确的方法。关于 Apple DocsreloadRows(...)应该在beginUpdates ... endUpdates.

那么,解决这个问题的正确方法是什么?

标签: iosswiftuitableview

解决方案


不完全确定你想要什么样的视觉效果,但是......

您可能想要重新加载表格视图,然后删除/重新排列行。

试试这样:

@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

推荐阅读