I am trying to select a single cell for each section. Everything works fine but when I scroll tableview to the bottom or top the checkmark accessory appears on random cells. Here is the code:
tableView.allowsMultipleSelection = true
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
// Find any selected row in this section
if let selectedIndexPath = tableView.indexPathsForSelectedRows?.first(where: { $0.section == indexPath.section}) {
// Deselect the row
tableView.deselectRow(at: selectedIndexPath, animated: false)
// deselectRow doesn't fire the delegate method so need to
// unset the checkmark here
tableView.cellForRow(at: selectedIndexPath)?.accessoryType = .none
}
return indexPath
}
func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
// Prevent deselection of a cell
return nil
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
any help would be appreciated to avoid this
CodePudding user response:
This happens because cells are reusable. I don't think its a good idea to call tableView.cellForRow
in didSelectRowAt
.You must control which indexPath are selected in cellForRowAt
Try this :
var selectedRows = [IndexPath]() // selected indexPaths array
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedRows.contains(indexPath){ // if already selected , remove
selectedRows = selectedRows.filter({$0 != indexPath})
}else{
selectedRows.append(indexPath)
}
tableView.reloadRows(at: [indexPath], with: .automatic)
}
And in your cellForRowAt
if selectedRows.contains(indexPath){
cell.accessoryType = .checkmark
}else{
cell.accessoryType = .none
}
CodePudding user response:
That is happening because you are making changes to on-screen cells without updating your model to reflect those changes. Then when a cell gets recycled, sometimes you pick up a cell that still has it's checkmark set.
Don't reach into cells and change their appearance. Instead, mark the cell as needing to be updated (by calling reloadRows(at:with)
) and then in your tableView(cellForRowAt:)
method, always set the accessory type to either .none
or .checkmark
.