iosswiftuitableviewmultiple-choiceindexpath

Select cell from a saved indexPath


I am trying to create a tableview that selects the cell using an indexPath.

I have saved the indexPath of selected cell & save it to my data array for each question. However when I reload the tableView how do I get the indexPath to change that particular cell's background view to how it looked when I select the previous button.

var dataArray: [MultipleChoice] = [
    MultipleChoice(
        question: "Question 1",
        options: ["Answer 1", "Answer 2", "Answer 3", "Answer 4"],
        rightAnswer: "Answer 1",
        subject: "General",
        idxPath: [0,0]),
    MultipleChoice(
        question: "Question 2",
        options: ["Answer 1", "Answer 2", "Answer 3", "Answer 4"],
        rightAnswer: "Answer 2",
        subject: "General",
        idxPath: [0,0]),


@IBAction func nextButtonPressed(_ sender: Any) {

    if var index = dataBrain.questionNumber {
        if index + 1 < dataBrain.dataArray.count {

            index += 1
            dataBrain.questionNumber = index
            scoreLabel.text = "\(dataBrain.questionNumber! + 1)/\(dataBrain.dataArray.count)"
            answerHidden = true
            table.reloadData()

        } 

}

@IBAction func previousButtonPressed(_ sender: Any) {

    if var index = dataBrain.questionNumber {
        if index - 1 >= 0 {

            index -= 1
            dataBrain.questionNumber = index
            scoreLabel.text = "\(dataBrain.questionNumber! + 1)/\(dataBrain.dataArray.count)"
            table.reloadData()

        }

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCell(withIdentifier: AnswerTableViewCell.identifier) as! AnswerTableViewCell

        //Load Options:
        if let index = dataBrain.questionNumber {
            let data = dataBrain.dataArray[index]
            cell.answerLabel.text = data.options![indexPath.row - 1]
            cell.selectionStyle = .none
        }

        //Load Right/Wrong Options
        let index = dataBrain.questionNumber
        let data = dataBrain.dataArray[index!]
        let rightAnswer = data.rightAnswer!

        if cell.answerLabel.text == rightAnswer {
            cell.confirmButton.setImage(UIImage(systemName: "checkmark.circle"), for: .normal)
            cell.confirmButton.imageView?.tintColor = UIColor.green
        } else {
            cell.confirmButton.setImage(UIImage(systemName: "xmark.circle"), for: .normal)
            cell.confirmButton.imageView?.tintColor = UIColor.red
        }

        //Load Background Color/Text
        cell.delegate = self
        cell.selectedBackgroundView = .none
        cell.confirmButton.isHidden = answerHidden

        let selectedCell = dataBrain.dataArray[index!].idxPath
        if selectedCell == [0,0] {
            cell.answerView.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
            cell.answerLabel.textColor = #colorLiteral(red: 0.4228360057, green: 0.4478931427, blue: 0.4731111526, alpha: 1)
        } else {
            table.selectRow(at: selectedCell, animated: false, scrollPosition: .none)
        }

        return cell

enter image description here enter image description here enter image description here


Solution

  • When you implement tableView(_ tableView: UITableView, cellForRowAt ..., your job is to return a cell for the given indexPath -- do not change the table. Your source of truth is dataBrain.dataArray -- get the information, put it in a cell, and return it. That's it.

    So, in this code:

    let selectedCell = dataBrain.dataArray[index!].idxPath
    if selectedCell == [0,0] {
        cell.answerView.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
        cell.answerLabel.textColor = #colorLiteral(red: 0.4228360057, green: 0.478931427, blue: 0.4731111526, alpha: 1)
    } else {
        table.selectRow(at: selectedCell, animated: false, scrollPosition: .none)
    }
    

    The if should be more like this:

    if selectedCell[0] == indexPath.section, selectedCell[1] == indexPath.row {
        // The cell I am making is selected -- set it up
    } else {
        // The cell I am making is not selected, set it up also
        // (it could be a reused cell that is colored for selection, so ALWAYS set the properties.
    }
    

    Do not call table.selectRow

    Now, when you want a cell to change, just reload it. Either reloadData (not ideal, but you can do it to make sure things work), or the other reload methods that target specific changes.