Beginning Table Views · Conclusion | Ray Wenderlich


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/5995-beginning-table-views/lessons/20

Hi, I think there is an error in the app. When you move the cells out of the screen with your fingers and then let them show again, they are recycled by calling tableView.dequeueReusableCell(). The problem is (in my opinion) that you call configureCheckmark() next, which changes the CheckListItem.checked every time you do this. Shoudn’t you have another function for setting the checkmark state for recycled cells, which just reads CheckListItem.checked, sets the cell.accessoryType accordingly, but doesn’t change its value?
Thank You,
Jan

I’ll have to check it out - thanks for the heads up.

I had the same bug that @honzakxt pointed out. I solved this for now by having the tableView.dequeueReusableCell() call a new method called getCheckmark(), which is essentially what @honzakxt suggested above. It is the same as configureCheckmark(), but without the call to toggle the checked value.

Not an ideal solution as it basically repeats the configureCheckbox code except for the one line. And so, I refactored the configureCheckmark method to call the getCheckmark method like so:

func configureCheckmark(for cell: UITableViewCell, with item: ChecklistItem) {
    item.toggleChecked()
    getCheckmark(for: cell, with: item)
  }
  
  func getCheckmark(for cell: UITableViewCell, with item: ChecklistItem) {
    if item.checked {
      cell.accessoryType = .checkmark
    } else {
      cell.accessoryType = .none
    }
  }

Lastly, I would note that I changed the code in the video to add the checkmark accessoryType when the item.checked it true and ‘none’ when checked is false.

@chuck_taylor Thank you for sharing your solution - much appreciated! :]

Same problem: Checkmarks will be reused in a random way when they go outside the visible area.

@danilolutti Do you still have issues with this?

Yes. You can test yourself by downloading the starter project of part 3 (Episode 22).

Hi chuck_taylor,

Even though I updated my code according to your suggestion, I still have an issue.

Below is my code. Could you please take a look and tell me what I did wrong here?
class ChecklistViewController: UITableViewController {

var todoList: TodoList

required init?(coder: NSCoder) {
    
    todoList = TodoList()
    super.init(coder: coder)
}

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return todoList.todos.count
}
 
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "ChecklistItem", for: indexPath)
    let item = todoList.todos[indexPath.row]
    
    configureText(for: cell, with: item)
    configureCheckmark(for: cell, with: item)
    
    
    return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if let cell = tableView.cellForRow(at: indexPath) {
        let item = todoList.todos[indexPath.row]
        configureCheckmark(for: cell, with: item)
        tableView.deselectRow(at: indexPath, animated: true)
        }
    }

func configureText(for cell: UITableViewCell, with item: ChecklistItem) {
     if let label = cell.viewWithTag(1000) as? UILabel {
        label.text = item.text
     }
}

func configureCheckmark(for cell: UITableViewCell, with item: ChecklistItem) {
    item.toggleChecked()
    getCheckmark(for: cell, with: item)
}

func getCheckmark(for cell: UITableViewCell, with item: ChecklistItem) {
    if item.checked {
        cell.accessoryType = .checkmark
    } else {
        cell.accessoryView = .none
    }
}

}

@nlplaw It may be because in your getCheckmark function, you wrote cell.accessoryView = .none instead of cell.accessoryType = .none