Casey West
Casey West

Reputation: 576

UISwitch in custom UITableViewCell Reuse Issue

The issue is as follows: I have a tableview with a custom cell. That cell contains a label and a UISwitch. I have set the label.text value to an array, but the UISwitch is getting reused.

Example: If I toggle the switch in the first row, the 5th row gets enabled, and if I scroll it continues to reuse the cells and cause issue.

Video : https://vimeo.com/247906440

View Controller:

class ViewController: UIViewController {

    let array = ["One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten"]

    @IBOutlet weak var tableView: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()

    }

}

extension ViewController: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
        cell.label.text = array[indexPath.row]
        return cell
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return array.count
    }
}

Custom Cell:

class CustomTableViewCell: UITableViewCell {

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var toggleSwitch: UISwitch!

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

}

I realize there isn't code trying to store this data because I haven't been successful. Any ideas would be helpful. The project currently uses the MVC model and I believe that is the answer but just need some help.

Upvotes: 0

Views: 1094

Answers (2)

Mukund Sarada
Mukund Sarada

Reputation: 156

I would recommend to you create cellViewModel class and keep array of it instead of just string. You cellViewModel may look like,

class CellViewModel {
 let title: String
 var isOn: Bool

init(withText text: String, isOn: Bool = false /* you can keep is at by default false*/) {
    self.title = text
    self.isOn = isOn
} 

Now, build array of CellViewModel

let array =["One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten"]
var cellViewModels = [CellViewModel]()
for text in array {
    let cellViewModel = CellViewModel(withText: text)
    cellViewModels.append(cellViewModel)
}

Change your tableVieDelegate function to :

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
    let cellViewModel = cellViewModels[indexPath.row]
    cell.label.text = cellViewModel.title
    cell.toggleSwitch.isOn = cellViewModel.isOn
    cell.delegate = self
    return cell
}

In you Custom Cell class, add this protocol :

protocol CellActionDelegate: class {
    func didChangeSwitchStateOnCell(_ cell: CustomTableViewCell)
}

Add delegate as property in your custom cell,

weak var delegate: CellActionDelegate?

Also, on switch change, add this line,

delegate?.didChangeSwitchStateOnCell(self)

Now, your viewController should register and listen to this delegate : I have added line cellForRowAtIndexPath to register for delegates. To listen this delegate, add this function in your VC.

func didChangeSwitchStateOnCell(_ cell: CustomTableViewCell) {
    let indexPath = tableView.indexPath(for: cell)
    cellViewModels[indexPath.row].isOn = cell.toggleSwitch.isOn
}

Upvotes: 3

Florian Ldt
Florian Ldt

Reputation: 1235

start creating a model for example :

struct item {
    var id: String
    var name: String
    var isActivated: Bool

    init(id: String, name: String, isActivated: Bool) {
        self.id = id
        self.name = name
        self.isActivated = isActivated
    }

}

let item1 = item(id: "1", name: "One", isActivated: false)
let item2 = ...........
let item3 = ...........
let items [item1, item2, item3]

With that you can trigger the boolean if it's activated or not.

You will also have to take a look to https://developer.apple.com/documentation/uikit/uitableviewcell/1623223-prepareforreuse I think.

Upvotes: 1

Related Questions