iosswiftuitableviewuiswitch

Allows to choose only one option switch button inside table view


What is the best or elegant way to validate state switch?

For example if I select the second option (NO), change the first option state (isOn to false) (SI)

I want to achieve that allows to choose only one option

I have this switch inside table view

extension QuestionListTableViewCell: UITableViewDelegate, UITableViewDataSource {
  
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return answers.count
  }
  
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "answerListCell", for: indexPath) as! AnswerListTableViewCell
    cell.separatorInset.right = cell.separatorInset.left
    cell.answerList.optionSwitch.tag = indexPath.row
    cell.answerList.optionSwitch.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)

    return cell
  }

  @objc func switchChanged(_ sender: UISwitch!){
    print("Table row switch Changed \(sender.tag)")
    print("The switch is \(sender.isOn ? "ON" : "OFF")")
  }
}

I load view from xib

class AnswerList: UIView {

  @IBOutlet weak var optionSwitch: UISwitch!
  @IBOutlet weak var optionLabel: UILabel!
  
  required init?(coder: NSCoder) {
    super.init(coder: coder)
    commonInit()
  }
  
  func commonInit(){
    let viewFromXib = Bundle.main.loadNibNamed("AnswerList", owner: self, options: nil)![0] as! UIView
    viewFromXib.frame = self.bounds
    addSubview(viewFromXib)
  }
  
  
  @IBAction func switchChangedState(_ sender: UISwitch) {

  }
  

}

enter image description here


Solution

  • You would want to add a property in your view controller that would keep track of the selected switch

    var selectedSwitchIndex: Int?

    And in your cellForRowAt method, set the selected switch to On and keep other switches off.

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "answerListCell", for: indexPath) as! AnswerListTableViewCell
        cell.separatorInset.right = cell.separatorInset.left
        cell.answerList.optionSwitch.tag = indexPath.row
        cell.answerList.optionSwitch.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
        let isSelected = indexPath.row == selectedSwitchIndex
        cell.answerList.optionSwitch.isOn = isSelected
    
        return cell
    

    And in your switchChanged method, set the selectedSwitchIndex property to switch index which is toggled and reload your table view.

    @objc func switchChanged(_ sender: UISwitch!){
        // you would want to save the index only when its set to on
        guard sender.isOn else {
            // setting the selectedSwitchIndex to nil if the switch is turned off
            selectedSwitchIndex = nil
            return 
        }
        selectedSwitchIndex = sender.tag
        tableView.reloadData()
    }