微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

每次出现新行时如何更新所有可见的 UITableViewCell

如何解决每次出现新行时如何更新所有可见的 UITableViewCell

我希望 UITableView 的刷新由新单元格的出现触发。

简单的设置。 UITableViewdataSource[Double]。表格中的每一行将在数组中显示一个数字。

我想做的特别的事情是我希望表格用所有可见单元格的最大数量标记单元格。然后每个其他单元格将计算与屏幕上最大数量的差异。并且每次出现新单元格时都会更新。

the demo of how it should look like

import UIKit

class ViewController: UIViewController {
    var max = 0.0
    var data:[Double] = [13,32,43,56,91,42,26,17,63,41,73,54,87,64,33,51,99,85,57,30,20]
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red
        self.tableView.dataSource = self
        self.tableView.delegate = self
        self.tableView.reloadData()
    }
    
    private func calculate() {
        // calculate the max of visible cells
        let indexes = tableView.indexPathsForVisibleRows!
        max = indexes
            .map { data[$0.row] }
            .reduce(0) { Swift.max($0,$1) }
        
        // trying to update all the visible cells.

//         tableView.reloadRows(at: indexes,with: .none) ****
//         tableView.reloadData() ****
        
    }
}

extension ViewController: UITableViewDataSource,UITableViewDelegate {
    func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
        data.count
    }
    
    func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell  = tableView.dequeueReusableCell(withIdentifier: "default")!
        cell.textLabel?.text = "\(data[indexPath.row]) : \(max)"
        return cell
    }
    
    func tableView(_ tableView: UITableView,heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 64
    }
    
    func tableView(_ tableView: UITableView,willdisplay cell: UITableViewCell,forRowAt indexPath: IndexPath) {
        calculate()
    }
    
    func tableView(_ tableView: UITableView,didEnddisplaying cell: UITableViewCell,forRowAt indexPath: IndexPath) {
        calculate()
    }
}

我做了什么

有 2 行代码以 **** 结尾。

如果我取消注释 tableView.reloadRows(at: indexes,with: .none),Xcode 会产生错误'NSRangeException',reason: '*** -[__NSArrayM objectAtIndexedSubscript:]: index 15 beyond bounds [0 .. 13]'。我真的不明白为什么,但我知道屏幕上的可见单元格最多 14 个才能适应屏幕,但是在表格加载阶段,模拟器认为在某些时候有 19 个可见单元格

如果相反,我取消注释 tableView.reloadData(),这行代码将触发 willdisplay func,它将再次调用 calculate func,其中包含 reloadData()。这是一个无限递归循环,没有一行成功显示在屏幕上。

如果相反,我不取消任何注释,表格将不会更新已经在屏幕上的单元格。只有新出现的单元格才能正确显示我想要的效果

感谢您阅读本文并尝试提供帮助。

解决方法

您不想调用 reloadCells,因为这会触发 willDisplay,然后您会陷入无限循环。

相反,您可以通过为可见单元格调用 cellForRow(at:) 来访问可见单元格并直接更新它。

private func updateVisibleCells() {
    for indexPath in self.tableView.indexPathsForVisibleRows ?? [] {
        if let cell = self.tableView.cellForRow(at: indexPath) {
            cell.textLabel?.text = "\(data[indexPath.row]) : \(max)"
        }
    }
}

现在,如果您在 updateVisibleCells 中调用 calculate() 之后直接调用 willDisplayCell,您将在控制台中收到一条消息:

尝试在表格视图上调用 -cellForRowAtIndexPath: 在更新其可见单元格的过程中,这是不允许的。

这会导致发布版本崩溃。

为了解决这个问题,我们可以通过异步分派它来推迟对 updateVisibleCells 的调用,以便在表视图更新完成后调用它:

func tableView(_ tableView: UITableView,didEndDisplaying cell: UITableViewCell,forRowAt indexPath: IndexPath) {
    self.calculate()
    DispatchQueue.main.async {
        self.updateVisibleCells()
    }
}

您希望使用 didEndDisplaying 而不是 willDisplay 以便在行滚出视图时正确更新行。 willDisplay

中不需要任何东西

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。