首页 > 解决方案 > 每次新单元出现时如何访问 UITableView.visibleCells

问题描述

我有一个 tableView 显示[Double]。很简单。但我也想显示每一行屏幕上数字的平均值,以及这个数字和平均值之间的差异

在此处输入图像描述

因为每次出现新行都需要重新计算平均值,所以我正在考虑tableView.visibleCellscellForRowAt: indexPath方法中访问,然后更新该行和屏幕上每隔一行的平均值,因为屏幕上的行的平均值应该是相同的对于所有屏幕上的行。

但后来我收到了这个错误信息 [Assert] Attempted to access the table view's visibleCells while they were in the process of being updated, which is not allowed. Make a symbolic breakpoint at UITableViewAlertForVisibleCellsAccessDuringUpdate to catch this in the debugger and see what caused this to occur. Perhaps you are trying to ask the table view for the visible cells from inside a table view callback about a specific row?

虽然这很响亮,但我想知道正确的方法或解决方法是什么?

代码很简单

class ViewController: UIViewController {
    
    var data:[Double] = [13,32,43,56,89,42,26,17,63,41,73,54,26,87,64,33,26,51,99,85,57,43,30,33,20]
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()        
        self.tableView.dataSource = self
        self.tableView.delegate = self
        
    }

}

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])"
        print(tableView.visibleCells.count) // THIS LINE PRODUCE ERROR
        return cell    
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 64
    }
    
}

我试过的:

我已经尝试过didEndDisplayingwillDisplay当我添加print(tableView.visibleCells.count)到其中任何一个时,都会返回相同的错误消息。

标签: iosswiftuitableview

解决方案


回答:

你可以使用 UITableView 的委托函数来计算这个。

tableView(_:willDisplay:forRowAt:)每次在单元格变得可见之前都会调用,因此您可以在此时重新计算平均值。此外,tableView(_:didEndDisplaying:forRowAt:)当单元格不显示时会触发,也可用于重新计算。


文档:

tableView(_:willDisplay:forRowAt:)

tableView(_:didEndDisplaying:forRowAt:)


升级版:

计算使用tableView.indexPathsForVisibleItems


例子:

import UIKit

class ViewController: UIViewController {
    
    var data:[Double] = [13,32,43,56,89,42,26,17,63,41,73,54,26,87,64,33,26,51,99,85,57,43,30,33,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() {
        let count = tableView.indexPathsForVisibleRows?.count
        let sum = tableView.indexPathsForVisibleRows?
            .map { data[$0.row] }
            .reduce(0) { $0 + $1 }
        
        if let count = count, let sum = sum {
            print(sum / Double(count))
        }
    }
}

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])"
        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()
    }
}

推荐阅读