ios – SOLVED: UIKit: Why is my indexPath off by one when calling tableView.indexPathForRow(at: to:)?

0
151


I’m noticing odd behavior in one of the UITableView methods (tableView.indexPathForRow(at: to:)) which is usually used to get the index path of a row that is interacted with in a UITableView. I’ve used this many times perfectly fine but on a new project (built with Xcode 14) it’s not working and the index is off by one.

I stripped everything down to the most basic elements and created a tag on a checkbox in my TestCell with the tag number set to the indexPath.row value created in cellForRowAt so I know that the cell is in the correct place.

The problem is when the testButton method is called, the indexPath given by tableView.indexPathForRow is off by one. This obviously crashes the app when I hit the button on the first cell, if I hit the button on the second cell the first row’s button toggles on.

I’ve already looked at all the other stack overflow questions regarding this and none were able to solve this issue. I’m not interested in a work around that’s easy enough, I’m trying to identify if this is indeed a bug on Apples end or a mistake in my code that I’ve overlooked. None of my other apps using this function built with earlier versions of Xcode have this issue.

import UIKit

class TestListViewController: UITableViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    configureTableView()
    }
}

extension TestListViewController {

    private func configureTableView() {
        tableView.register(TestCell.self, forCellReuseIdentifier: "TestCell")
    }

    @objc func testButton(_ sender: UIButton) {
      
        guard let indexPath = tableView.indexPathForRow(at: sender.convert(CGPoint.zero, to: self.tableView)) else {
            return
        }
        print("Tag: \(sender.tag)") //This comes up as expected
        print("IndexPath: \(indexPath)")    //This does not, index is off by one! 
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    
        let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as! TestCell
    
        cell.nameLabel.text = "Row \(indexPath.row)"
        cell.checkbox.addTarget(self, action: #selector(testButton(_ :)), for: .touchUpInside)
        cell.checkbox.tag = indexPath.row
   
        return cell
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 50
    }
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
}