1

I have a tableview with multiple sections each section is having 3 cells , each cell contains the custom check mark button. Where user can change check and uncheck images of check button on click. The problem is, i am changing the cell button image from uncheck to check when user click on button which is working fine. If i scroll the tableview that check mark image is adding to wrong cell.

I googled it and found the solution like saving clicked cell indexPath.row in array and removing from array if user click again on same cell. It is not working as i have multiple sections.

Please provide me any suggestion to find out the solution for my problem.

// Button action.

func buttonTappedOnCell(cell: customeCell) {
        let indexPath : IndexPath = self.tableView.indexPath(for: cell)!

        if self.selectedIndexPath.count > 0 {

        for  selectedIndex in self.selectedIndexPath {

            if selectedIndex as! IndexPath == indexPath {

                self.selectedIndexPath.remove(indexPath)
            } else {

                self.selectedIndexPath.add(indexPath)
            }
        }
        } else {
            self.selectedIndexPath.add(indexPath)
    }

Code in cellForRowAtIndexPath

    for anIndex  in self.selectedIndexPath {

        if anIndex as! IndexPath == indexPath {
            cell.checkMarkButton.setBackgroundImage(UIImage(named: "checkMark"), for: .normal)
        } else {
            cell.checkMarkButton.setBackgroundImage(UIImage(named: "UnCheckMark"), for: .normal)
        }
    }
Paulw11
  • 108,386
  • 14
  • 159
  • 186
Logger
  • 1,274
  • 1
  • 14
  • 25

3 Answers3

3

You can simplify your code greatly by using a Set<IndexPath>. There is no need to loop through an array.

var selectedPaths=Set<IndexPath>()

func buttonTappedOnCell(cell: customeCell) {

   if let indexPath = self.tableView.indexPath(for: cell) {
       var image = UIImage(named: "CheckMark")
       if self.selectedPaths.contains(indexPath) {
           image = UIImage(named: "UnCheckMark")
           self.selectedPaths.remove(indexPath)
       } else {
           self.selectedPaths.insert(indexPath)
       }

       cell.checkMarkButton.setBackgroundImage(image, for: .normal)
   }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as! YourCellType

    ...

    var image = UIImage(named: "UnCheckMark")
    if self.selectedPaths.contains(indexPath) {
       image = UIImage(named: "checkMark")
    }

    cell.checkMarkButton.setBackgroundImage(image, for: .normal)

    return cell
}
Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • Thanks for your quick reply. It is working great and need small correction to your answer where need to change image name from checkMark to UnCheckMark in the following if condition.if self.selectedPaths.contains(indexPath) { Because if NSSet contains indexPath we need to Uncheck the checkmark – Logger Apr 17 '17 at 08:49
  • Sorry. I got that the wrong way around. I'll update it. – Paulw11 Apr 17 '17 at 09:19
  • @objc func checkBoxTapped(cell : CheckboxCell){ if let indexPath = self.tableView.indexPath(for: cell) as CheckboxCell{}} // cannot convert value of type indexpath to type checkboxcell in coercion error, any idea? – Mac_Play Jul 23 '18 at 08:27
  • `indexPath(for:)` returns an `IndexPath` not a `UITableViewCell` so your downcast is invalid. – Paulw11 Jul 23 '18 at 08:31
  • YourCellType this means? Can you please update the code? – Mac_Play Jul 23 '18 at 08:36
  • 1
    Sorry, that was a typo. There is no need for a downcast there. – Paulw11 Jul 23 '18 at 08:46
  • indexPath always returns nil. Any idea? – Mac_Play Jul 23 '18 at 12:24
  • You should ask your own question, including relevant code – Paulw11 Jul 23 '18 at 12:54
1

This happens because the cells of a tableView are reused to minimise memory usage.

If you are using a custom implementation of check button then you have to store the values for the cell which is selected in a data Structure like an array for example if you have 2 sections with 3 elements in each section with 2nd item in 1st section selected, then the data structure like an array can be like [[false, true, false], [false, false. false]]. Here I am setting true in case the cell is selected. Update the values of this data structure and check from it when applying the image in the cellForRowAt and apply the checkedImage only when the indexPath.section and indexPath.row for Array return a true Bool.

Hope this helps. Feel free to reach out in case of any doubts. Happy coding.

Md. Ibrahim Hassan
  • 5,359
  • 1
  • 25
  • 45
-2

inside of your TableView DidSelect method just put

let cell = tableView.cellForRowAtIndex(indexPath).accessoryType = UITableViewCell.accessoryType = Checkmark

vice versa for DidDeselect method but change the Checkmark into None.

let cell = tableView.cellForRowAtIndex(indexPath).accessoryType = UITableViewCell.accessoryType = None

If you create more complex code for a simple method, It'll give you disaster.

Gabriel M.
  • 90
  • 5