Reputation: 111
I have a UITableView with custom UITableViewCells containing UIButtons. The UITableView needs to be reloaded every second. However, when tapping rapidly on a cell, I've noticed that sometimes the wrong index path is being printed. To troubleshoot this issue, I've attempted to clean up the cell in the prepareForReuse method by resetting properties such as the index path and button target-action associations. However, this approach doesn't seem to resolve the problem completely.
I've found that removing cell reuse or recreating the button each time in prepareForReuse solves the issue, but I'm trying to understand why simply cleaning up the cell in prepareForReuse doesn't work as expected.
Does anyone have insights into why the cell cleanup in prepareForReuse might not be effective in preventing the wrong index path from being printed?
Gif: https://jumpshare.com/s/LXidDSnUXPPQoNUIau8a (I'm clicking on the third cell and sometimes getting 0-4 instead of 0-2. Then, on the fifth cell, I sometimes get 0-6 instead of 0-4.)
class ViewController: UIViewController, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
var timer: Timer?
var val = 0
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.register(TableViewCell.self, forCellReuseIdentifier: "cell")
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateData), userInfo: nil, repeats: true)
timer?.fire()
}
deinit {
timer?.invalidate()
}
@objc func updateData() {
val += 1
tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.indexPath = indexPath
cell.configure(val: indexPath.row + val)
cell.delegate = self
return cell
}
}
extension ViewController: TableViewCellDelegate {
func didTap(cell: UITableViewCell) {
let indexPath = tableView.indexPath(for: cell)
print("indexPath = \(indexPath)")
}
}
cell:
protocol TableViewCellDelegate: AnyObject {
func didTap(cell: UITableViewCell)
}
class TableViewCell: UITableViewCell {
var button: UIButton = UIButton()
var indexPath: IndexPath?
weak var delegate: TableViewCellDelegate?
override func prepareForReuse() {
super.prepareForReuse()
indexPath = nil
delegate = nil
button.removeTarget(nil, action: nil, for: .allTouchEvents)
// button = UIButton()
}
func configure(val: Int) {
if button.superview == nil {
contentView.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.topAnchor.constraint(equalTo: contentView.topAnchor),
button.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
button.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
button.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
}
button.setTitle("push me \(val)", for: .normal)
button.addTarget(self, action: #selector(tap), for: .touchUpInside)
button.backgroundColor = .red
}
@objc func tap() {
delegate?.didTap(cell: self)
}
}
Upvotes: 0
Views: 36