0

I have a function inside a protocol that takes a TableViewcell as an argument.

protocol GoingButtonDelegate {
    func goingButtonPressed(cell: TableViewCell)
}

class TableViewCell: UITableViewCell {
    // Outlets
    @IBOutlet weak var goingButton: UIButton!

    var delegate: GoingButtonDelegate?

    @IBAction func goingButtonTapped(_ sender: Any) {
        delegate?.goingButtonPressed(cell: self)  
    }

I then go over to my ViewController and implement the delegate and it's function, which is to change the image of a button when tapped. The "goingSelected" is a green image and the "goingDeselected" is a red image.

This all works out fine, when tapped the button of a cell goes from red to green and vice versa. However, when the cell gets reused, the button state of the cell persists and gets reused for the new row that enters view. Is there any way to stop this from happening?

 extension ViewController: GoingButtonDelegate {
    func goingButtonPressed(cell: TableViewCell) {
        cell.goingButton.isSelected = !cell.goingButton.isSelected

        if cell.goingButton.isSelected == true {
            cell.goingButton.setImage(UIImage(named: "goingSelected"), for: UIControlState.selected)
        } else if cell.goingButton.isSelected == false {
            cell.goingButton.setImage(UIImage(named: "goingDeselected"), for: UIControlState.normal)
        }
    }
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
Kauna Mohammed
  • 797
  • 1
  • 6
  • 14
  • 1
    Possible duplicate of [How to prevent UITableView from reuse custom cells Swift](https://stackoverflow.com/questions/37938809/how-to-prevent-uitableview-from-reuse-custom-cells-swift) –  Sep 03 '17 at 18:32
  • You do not want to avoid reusing cells. That's not the proper solution. – rmaddy Sep 03 '17 at 19:19

2 Answers2

0

It's possible

just replace

let cell = tableView.dequeueReusableCell(withIdentifier: identifier,
  for: indexPath)

with:

let cell= Bundle.main.loadNibNamed(identifier, owner: self, options: nil)?[0]

but I think you need to change your app logic.

Set Images inside of your cell class

class TableViewCell: UITableViewCell {
  override func awakeFromNib() {
    super.awakeFromNib()
    self.goingButton.setImage(UIImage(named: "goingDeselected"), for:.normal)
    self.goingButton.setImage(UIImage(named: "goingSelected"), for:.selected)
  }
}

and in method goingButtonPressed(cell: TableViewCell) change cell to your object and just set Bool type true or false

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  ...
  cell.goingButton.isSelected = object.isSelected
  ...
}
Yerken
  • 299
  • 1
  • 12
0

You need to store the selected rows in an array of index paths, before that I think you should make few enhancements ... or a lot!!

the cell itself should handle it's button, the controller should just keep track of all cells status. Add these two properties to your cell

class TableViewCell: UITableViewCell {
    var indexPath:IndexPath?
    var isSelected : Bool = false {
        didSet{
            if isSelected {
                cell.goingButton.setImage(UIImage(named: "goingSelected"), for: UIControlState.normal)
            } else {
                cell.goingButton.setImage(UIImage(named: "goingDeselected"), for: UIControlState.normal)
            }
        }
    }
    // Outlets
    @IBOutlet weak var goingButton: UIButton!

    var delegate: GoingButtonDelegate?

    @IBAction func goingButtonTapped(_ sender: Any) {
        self.isSelected = !self.isSelected
        delegate?.goingButtonPressed(cell: self)  
    }
    ..
    ...
}

And store the selected cells in your view controller to keep track of each cell status.

extension ViewController: GoingButtonDelegate {
    var selectedCells = NSMutableArray()
    func goingButtonPressed(cell: TableViewCell) {
        if cell.isSelected {
            selectedCells.add(cell.indexPath)
        } else {
            selectedCells.remove(cell.indexPath)
        }
    }
}

and in your "cell for row" method just add a small change

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "yourCellIdentifier") as! TableViewCell
    cell.indexPath = indexPath
    cell.isSelected = selectedCells.contains(indexPath)
    ..
    ...
    return cell
}