-1

I have a table with multiple cells using the same cell class. This class includes a UISwitch.

My table has two sections. The first section only has 6 cells, but the second has 11.

There is something about this magic number 11 which is causing strange behaviour in my app. Whenever I toggle the first switch in the second section, the 11th switch toggles as well. This is also true if I toggle the 11th switch, the first is toggled automatically with it. The first and 11th cells in the second section are the only cells that exhibit this behavior.

I'm assuming it has something to do with the index path numbers, but I don't know where to start. Here's my code:

import UIKit

class ScoringSetupViewController: UIViewController, UITableViewDataSource, 
UITableViewDelegate, SwitchChangedDelegate {

@IBOutlet weak var scoringCategoriesTableView: UITableView!

let primaryCategories:[String] = ["Average Headshot Kills", "Average Kill Place", "Average Win Place", "Total Steak Dinners", "Total Chicken Dinners", "Average Total Kills"]
let secondaryCategories:[String] = ["Average Assists","Highest Assists","Average Damage Delt", "Highest Damage Delt", "Total Kill Streaks", "Highest Total Kills", "Highest Headshot Kills", "Longest Distance Kill", "Average Revives", "Total Road Kills", "Average Time Survived"]

var acceptedPrimaryCategories:[String:Bool] = ["Average Headshot Kills":true, "Average Kill Place":true, "Average Win Place":true, "Total Steak Dinners":true, "Total Chicken Dinners":true, "Average Total Kills":true]
var acceptedSecondaryCategories:[String:Bool] = ["Average Assists":true,"Highest Assists":true,"Average Damage Delt":true, "Highest Damage Delt":true, "Total Kill Streaks":true, "Highest Total Kills":true, "Highest Headshot Kills":true, "Longest Distance Kill":true, "Average Revives":true, "Total Road Kills":true, "Average Time Survived":true]

override func viewDidLoad() {
    super.viewDidLoad()
    scoringCategoriesTableView.dataSource = self
    scoringCategoriesTableView.delegate = self

}

func changeStateTo(isOn: Bool, section: Int, row: Int) {
    if section == 0 {
        if row == 0 {
            acceptedPrimaryCategories["Average Headshot Kills"] = isOn
        } else if row == 1 {
            acceptedPrimaryCategories["Average Kill Place"] = isOn
        } else if row == 2 {
            acceptedPrimaryCategories["Average Win Place"] = isOn
        } else if row == 3 {
            acceptedPrimaryCategories["Total Steak Dinners"] = isOn
        } else if row == 4 {
            acceptedPrimaryCategories["Total Chicken Dinners"] = isOn
        } else if row == 5 {
            acceptedPrimaryCategories["Average Total Kills"] = isOn
        }
        print(acceptedPrimaryCategories)
    } else if section == 1 {
        if row == 0 {
            acceptedSecondaryCategories["Average Assists"] = isOn
        } else if row == 1 {
            acceptedSecondaryCategories["Highest Assists"] = isOn
        } else if row == 2 {
            acceptedSecondaryCategories["Average Damage Delt"] = isOn
        } else if row == 3 {
            acceptedSecondaryCategories["Highest Damage Delt"] = isOn
        } else if row == 4 {
            acceptedSecondaryCategories["Total Kill Streaks"] = isOn
        } else if row == 5 {
            acceptedSecondaryCategories["Highest Total Kills"] = isOn
        } else if row == 6 {
            acceptedSecondaryCategories["Highest Headshot Kills"] = isOn
        } else if row == 7 {
            acceptedSecondaryCategories["Longest Distance Kill"] = isOn
        } else if row == 8 {
            acceptedSecondaryCategories["Average Revives"] = isOn
        } else if row == 9 {
            acceptedSecondaryCategories["Total Road Kills"] = isOn
        } else if row == 10 {
            acceptedSecondaryCategories["Average Time Survived"] = isOn
        }
        print(acceptedSecondaryCategories)
    }
}

@IBAction func continueButtonTapped(_ sender: Any) {

}

func numberOfSections(in tableView: UITableView) -> Int {
    return 2
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 60
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    if section == 0 {
        return "Primary Scoring Categories"
    } else if section == 1 {
        return "Secondary Scoring Cagtegories"
    } else {
        return ""
    }
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if section == 0 {
        return primaryCategories.count
    } else if section == 1 {
        return secondaryCategories.count
    } else {
        return 0
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "scoringCategoryCell", for: indexPath) as! ScoringCategoryTableViewCell
    cell.delegate = self
    cell.section = indexPath.section
    cell.row = indexPath.row

    if indexPath.section == 0 {
        cell.categoryNameLabel.text = primaryCategories[indexPath.row]
    } else if indexPath.section == 1 {
        cell.categoryNameLabel.text = secondaryCategories[indexPath.row]
    }
    return cell

    return UITableViewCell()
}

}

And the table cell custom class

import UIKit

protocol SwitchChangedDelegate {
func changeStateTo(isOn: Bool, section: Int, row: Int)
}

class ScoringCategoryTableViewCell: UITableViewCell {
@IBOutlet weak var categoryNameLabel: UILabel!
@IBOutlet weak var categorySwitch: UISwitch!

var delegate: SwitchChangedDelegate?
var section: Int?
var row: Int?

override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
}


@IBAction func switchToggled(_ sender: UISwitch) {
    if sender.isOn {
        self.delegate?.changeStateTo(isOn: true, section: section!, row: row!)
    } else {
        self.delegate?.changeStateTo(isOn: false, section: section!, row: row!)
    }
}

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

    // Configure the view for the selected state
}

}

picciano
  • 22,341
  • 9
  • 69
  • 82
Alex Ritter
  • 1,009
  • 3
  • 18
  • 40

1 Answers1

1

The reason is cell reusing so in cellForRow you have to handle that

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   let cell = tableView.dequeueReusableCell(withIdentifier: "scoringCategoryCell", for: indexPath) as! ScoringCategoryTableViewCell
   cell.delegate = self
   cell.section = indexPath.section
   cell.row = indexPath.row
   cell.categorySwitch.isOn = // value
}

//

Also here

func changeStateTo(isOn: Bool, section: Int, row: Int)

its compact to send

func changeStateTo(isOn: Bool, indexPath:IndexPath)

Or

func changeStateTo(cell:ScoringCategoryTableViewCell) // ask cell for it's indexPath and then access all it's current properties 

and build your model in a way that access the value with subscript [] , not by checking value of dictionary

//

here

return cell

return UITableViewCell()

second line is useless

Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • Thanks for taking a look at this @Sh_Khan. When I add the line "cell.categorySwitch.isOn = true" in cellForRowAt, I get a crash for "Unexpectedly found nil while unwrapping an Optional value". Am I not reading your suggestion right? – Alex Ritter Apr 20 '18 at 18:15
  • connect the switch to IB or xib – Shehata Gamal Apr 20 '18 at 18:18
  • 1
    That was it. I had removed the connection earlier, but forgetting to delete the variable inside the custom table cell. Relinking the outlet made it work like a charm. Thanks. – Alex Ritter Apr 20 '18 at 18:20