Reputation: 6533
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:
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.
Upvotes: 0
Views: 1021
Reputation: 285290
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.
Upvotes: 1