iosswiftuitableviewuibuttonuisearchbar

iOS tableview cell button selection strange behavior


In tableview, each cell has a bookmark image button. When tapping on it, it becomes in a selected state and the image (red bookmark icon) is shown. I have delegate method to add information in cells with selected buttons to an array:

protocol CustomPoetCellDelegate {
func cell(_ cell: CustomPoetCell, didTabFavIconFor button: UIButton)
}

class CustomPoetCell: UITableViewCell {

@IBOutlet weak var poetNameLabel: UILabel!
@IBOutlet weak var verseCountLabel: UILabel!
@IBOutlet weak var periodLabel: UILabel!
@IBOutlet weak var iconButton: UIButton!

var delegate: CustomPoetCellDelegate?

override func awakeFromNib() {
    super.awakeFromNib()

    iconButton.setImage(UIImage(named: "icons8-bookmark-50-red.png"), for: .selected)
    iconButton.setImage(UIImage(named: "icons8-bookmark-50.png"), for: .normal)

    iconButton.isSelected = false
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
}

@IBAction func favIconTapped(_ sender: UIButton) {
    delegate?.cell(self, didTabFavIconFor: sender)
}

}

In tableViewController:

func cell(_ cell: CustomPoetCell, didTabFavIconFor button: UIButton) {
    if !button.isSelected {
        let indexPathRow = tableView.indexPath(for: cell)!.row

        if isFiltering() {
            favoritePoets.append(searchResults[indexPathRow])
            button.isSelected = true
        } else {
            favoritePoets.append(poets[indexPathRow])
            button.isSelected = true
        }
    } else {
        button.isSelected = false

        favoritePoets = favoritePoets.filter { $0.arabicName !=  cell.poetNameLabel.text}
    }
}

isFiltering() method checks if searchBar is in process.

Now, if isFiltering() is false, everything is fine, but if isFiltering() is true (that is, searching for a name in tableView), when I tap on a specific cell button to select it and then click cancel to dismiss the searchBar, icons for other cells are also selected, in spite of that only the one I tapped is added to the array. When navigating back and forth from the view, wrong selections are gone and only the right one is selected.

Any idea on what's going on?

Thanks in advance.


Solution

  • The problem is that the UITableView re-uses cell for optimized scroll performance. Hence it re-uses the cell which is not in view anymore with a new cell about to be displayed. Therefore you need to set the state of the cell when ever it is updated/reused.

    The following function is called everytime. So you need to set cell properties for selected or non-selected state over here.

         func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
            ...
            cell.indexPath = indexPath  //Create an indexPath property in your cell and set it here
                                       //This will be required when you call the delegate method
    
            //configure your cell state
    
            return cell
       }
    

    You can update your models in favoritePoets array by changing the specific property in delegate method that you are already calling for e.g

      favoritePoets[indexPath.row].selected = true or false
    

    For accessing the indexPath you need to set it as mentioned in above code. And then pass it as an argument in your delegate method. Now this updated property will help you set your state in cellForRowAt function.

    Hope it helps :). Feel free to comment.