Tableview didSelectRowAt wrongly selects row with JSON data in swift

47 Views Asked by At

I am trying to select a tableview row with a checkbox. However, if I select the first cell, then the second cell is selected. If I select the second cell, the third cell is selected, and if I select the third cell, then the first cell is selected. Why is this happening? Can you help me correct this issue?

Code:

extension StudentSignupStep4ViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        subscriptionList?.result?.subscriptionData?.count ?? 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: SubscriptionTableViewCell.cellId, for: indexPath) as! SubscriptionTableViewCell
        let cellData = subscriptionList?.result?.subscriptionData?[indexPath.row]
        cell.subscriptionNameLabel.text = cellData?.subscription_name
     
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let subscriptionData = subscriptionList?.result?.subscriptionData else { return }
        for i in subscriptionData.indices {
            if let cell = tableView.cellForRow(at: IndexPath(row: i, section: 0)) as? SubscriptionTableViewCell {
                cell.isChecked = i == indexPath.row
            }
        }
        tableView.reloadData()
        subsciptionId = subscriptionList?.result?.subscriptionData?[indexPath.row].id
    }
}

class SubscriptionTableViewCell: UITableViewCell {
    
    @IBOutlet weak var checkboxImageView: UIImageView!
    var isChecked = false {
        didSet {
            checkboxImageView.image = UIImage(systemName: (isChecked) ? "checkmark.square.fill": "square")
            checkboxImageView.tintColor = (isChecked) ? .myAccentColor: .lightGray
        }
    }
    override func awakeFromNib() {
        super.awakeFromNib()
    }
}
1

There are 1 best solutions below

0
matt On BEST ANSWER

Your error is here:

    for i in subscriptionData.indices {
        if let cell = tableView.cellForRow(at: IndexPath(row: i, section: 0)) as? SubscriptionTableViewCell {
            cell.isChecked = i == indexPath.row
        }
    }

That is completely wrong. Do not talk to the cells directly in this way, ever. Talk only to the data model (subscriptionList?.result?.subscriptionData). Then reload the table view, and let cellForRow read the data model for the individual index path and configure the cell accordingly (as it is already doing).

And delete the cell's isChecked property. A cell is view, and a highly volatile view at that (because cells, as you've been told, are reused); a cell must not make any attempt to maintain state.