0

I have reviewed this link and the solutions were not working for me.

I am trying to select one row and when I do select it, it adds a checkmark to the label. If another row is selected while there is an existing checkmark, it will uncheck the previous one which is stored in a selectedIndexPath variable.

It works in the beginning, however when scrolling through the tableview several times, I occasionally see a cell selected that should not be as indicated in this image:

enter image description here

What I am doing when a user selects a cell:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    if let cell = tableView.cellForRow(at: indexPath) as? CustomCell {
        let customCell = customCellData[indexPath.row]
        customCell.toggleSelected()
        cell.configureCheckmark(with: customCell)
    }

    if let oldIndexPath = selectedIndexPath, let cell = tableView.cellForRow(at: oldIndexPath) as? CustomCell, oldIndexPath.row != indexPath.row {
        let customCell = customCellData[oldIndexPath.row]
        customCell.toggleSelected()
        cell.configureCheckmark(with: customCell)
    }


    if let selected = selectedIndexPath, selected.row == indexPath.row {
        selectedIndexPath = nil
        tableView.deselectRow(at: indexPath, animated: true)
    } else {
        selectedIndexPath = indexPath
    }

}

and in for cellForRowAt: (is it redundant to check the selectedIndexPath and the state in the model?)

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
    let customCell = customCellData[indexPath.row]
    cell.customCell = customCell
    if selectedIndexPath == indexPath {
        cell.checkLabel.text = "✔️"
    } else {
        cell.checkLabel.text = ""
    }

    return cell
}

and finally in the CustomCell:

var customCell: CustomCell? {
    didSet {
        if let customCell = customCell {
            configureCheckmark(with: customCell)
        }
    }
}

func configureCheckmark(with customCell: CustomCellData) {
    if customCell.isSelected {
        checkLabel.text = "✔️"
    } else {
        checkLabel.text = ""
    }
}

In CustomCellData I toggle the state as follows:

class CustomCellData {
    var isSelected = false

    func toggleSelected() {
       isSelected = !isSelected
    }
}

I am scratching my head on this and unsure what to do, any help would be great.

Community
  • 1
  • 1
Simon
  • 6,413
  • 6
  • 34
  • 57

1 Answers1

1

The easiest solution is to reduce didSelectRowAt to

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
{
    selectedIndexPath = indexPath
    tableView.reloadData()
}

This updates all visible cells properly.

Or more sophisticated version which updates only the affected rows and checks if the cell is already selected

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
    if selectedIndexPath != indexPath  {
        let indexPathsToReload = selectedIndexPath == nil ? [indexPath] : [selectedIndexPath!, indexPath]
        selectedIndexPath = indexPath
        tableView.reloadRows(at: indexPathsToReload, with: .none)
    } else {
        selectedIndexPath = nil
        tableView.reloadRows(at: [indexPath], with: .none)
    }
}

The code in cellForRowAt does the rest.

vadian
  • 274,689
  • 30
  • 353
  • 361
  • This works but, if I wanted to uncheck the same cell selected, how would I go about doing that? Would I set the `selectedIndexPath` to `nil` if they are the same? – Simon Apr 21 '17 at 17:20
  • I updated the answer. Btw: The custom code to handle the checkmark in `CustomCellData` is not needed either. – vadian Apr 21 '17 at 17:25