Neulio
Neulio

Reputation: 332

How can I stop my UITableView from reusing cells?

I have a UITableView containing about 30 cells. The user is only able to select one. Once a cell is selected it shows a checkmark. But the problem is whenever I scroll down the UITableView it shows cells i never clicked with a checkmark beside them. What is the proper way to fix this?

override func numberOfSections(in tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return breedNameArray.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
    let cell = tableView.dequeueReusableCell(withIdentifier: "Bcell", for: indexPath)
    //cell.accessoryType = UITableViewCell.AccessoryType.checkmark
    cell.textLabel?.text = breedNameArray[indexPath.item]
    return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
   tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
    tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
    tableView.register(UINib(nibName: "BBcell", bundle: nil), forCellReuseIdentifier: "Cell")
    //let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
    //tableView.deselectRow(at: tableView.indexPathForSelectedRow!, animated: true)
    tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
    //let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
    tableView.cellForRow(at: indexPath)?.accessoryType = .none
}

Upvotes: 0

Views: 102

Answers (1)

Tyler Wood
Tyler Wood

Reputation: 136

The reason you are seeing cells getting checkmarks when scrolling is because the call to tableView.dequeueReusableCell(withIdentifier:"Bcell", for: indexPath) in cellForRowAt reuses already allocated UITableViewCell objects that have the identifier "Bcell". The UITableView does not automatically reset the properties of the reused UITableViewCell objects when reused in this way.

Since you are only allowing one UITableViewCell to be selected at a time, a simple solution would be to add a local variable to keep track of the selected IndexPath, and then use the local variable to set the accessoryType accordingly in cellForRowAt. Here is the code to illustrate what I mean:

// The local variable to keep track of the selected IndexPath
var selectedIndexPath = IndexPath()

override func numberOfSections(in tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return breedNameArray.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
    let cell = tableView.dequeueReusableCell(withIdentifier: "Bcell", for: indexPath)

    // Use selectedIndexPath to set the accessoryType as .checkmark or .none
    if indexPath == selectedIndexPath {
        cell.accessoryType = UITableViewCell.AccessoryType.checkmark
    } else {
        cell.accessoryType = UITableViewCell.AccessoryType.none
    }

    cell.textLabel?.text = breedNameArray[indexPath.item]
    return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    // Set the selectedIndexPath
    selectedIndexPath = indexPath

   tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
    tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
    tableView.register(UINib(nibName: "BBcell", bundle: nil), forCellReuseIdentifier: "Cell")
    //let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
    //tableView.deselectRow(at: tableView.indexPathForSelectedRow!, animated: true)
    tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}

override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {

    // Un-Set the selectedIndexPath
    selectedIndexPath = IndexPath()

    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Bcell")
    //let cell = tableView.dequeueReusableCell(withIdentifier: "Breeds", for: indexPath)
    tableView.cellForRow(at: indexPath)?.accessoryType = .none
}

Upvotes: 1

Related Questions