Heelow
Heelow

Reputation: 23

Swift 3 - Problems in reusing cell with multiple custom cells

I've got problems when I scroll down in my UITableview. The table shows me cells with old content when the cell is reused.

The Probleme is the following:

Swift wants to reuse an old cell, but doesn't properly clear the old content from the old cell. This leads to cells with old content, although I'm providing new data to the cells.

Architecture of the UITableView if the following:

Screenshots of the problem:

Beginning of the Questionnaire Screen Shot:

Screen Shot

The scrolled down table:

Screen Shot

The problem here is the "Handedness"-Cell which is showing the cell number 3 (because of the reuse of the cell), which is not right

The numberOfSection-Method

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

The numberOfRowsInSection-Method

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

The cellForRowAt-Method

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

    // first section is the normal Questionnaire
    if(indexPath.section == 0){

        // current questionnaireStructure
        let questStruct:QuestionnaireStructure? = questionnaireStructure[indexPath.row]

        // current cell is a "Headline"
        if(questStruct?.elementtype == "elements/headlines"){
            let cell = tableView.dequeueReusableCell(withIdentifier: "HeadlineStructureCellID", for: indexPath) as! Headline
            cell.headline.text = questStruct?.headline
            cell.selectionStyle = UITableViewCellSelectionStyle.none
            return cell
        } else if(questStruct?.elementtype == "elements/texts"){
            // current cell is a "texts"
            let cell = tableView.dequeueReusableCell(withIdentifier: "TextsStructureCellID", for: indexPath) as! Texts
            cell.textsLabel.text = questStruct?.text
            cell.selectionStyle = UITableViewCellSelectionStyle.none
            return cell
        } else if(questStruct?.questiontype == "Slider"){
            // currrent cell is a "slider-Question"
            let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionSliderStructureCellID", for: indexPath) as! Slider
            cell.sliderQuestion.text = questStruct?.question
            cell.selectionStyle = UITableViewCellSelectionStyle.none

            let values = (questStruct?.values)!
            let valueArray = values.array as! [Values]
            cell.slider.minimumValue = Float(valueArray[0].min)
            cell.slider.maximumValue = Float(valueArray[0].max)
            let answers = (questStruct?.answers)!
            let answerArray = answers.array as! [Answers]
            cell.minLabel.text = answerArray[0].label
            cell.maxLabel.text = answerArray[1].label

            return cell
        } else if(questStruct?.questiontype == "SingleChoice"){
            let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionSingleChoiceStructureCellID", for: indexPath) as! SingleChoiceCell
            let radioButtonController = SSRadioButtonsController()
            radioButtonController.delegate = self
            radioButtonController.shouldLetDeSelect = true
            cell.radioButtonController = radioButtonController
            cell.updateCellData(questStruct: questStruct!, indexInTable: indexPath.row)

            return cell
        } else if(questStruct?.questiontype == "MultipleChoice"){
            let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionMultipleChoiceStructureCellID", for: indexPath) as! MultipleChoiceCell
            cell.multQuestionLabel.text = questStruct?.question
            cell.questStruct = questStruct

            return cell
        } else if(questStruct?.questiontype == "YesNoSwitch"){
            let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionYesNoSwitchStructureCellID", for: indexPath) as! YesNoSwitch
            cell.yesNoQuestion.text = questStruct?.question
            cell.selectionStyle = UITableViewCellSelectionStyle.none

            return cell
        } else if(questStruct?.questiontype == "TextDate"){
            let cell = tableView.dequeueReusableCell(withIdentifier: "Datepicker", for: indexPath) as! DatePicker
            cell.question.text = questStruct?.question
            cell.selectionStyle = UITableViewCellSelectionStyle.none

            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionSingleChoiceStructureCellID", for: indexPath) as! SingleChoiceCell
            //cell.singleChoiceLabel.text = questStruct?.question
            cell.selectionStyle = UITableViewCellSelectionStyle.none
            return cell
        }

    } else {
        //last section is the save button
        // show the save button when the Questionnaire is loaded
        if(questionnaireStructure.count != 0){
            let cell = tableView.dequeueReusableCell(withIdentifier: "SaveStructureCellID", for: indexPath) as! SaveQuestionnaire
            cell.selectionStyle = UITableViewCellSelectionStyle.none
            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "TextsStructureCellID", for: indexPath) as! Texts
            cell.selectionStyle = UITableViewCellSelectionStyle.none
            return cell
        }
    }

}

What I checked:

Upvotes: 2

Views: 5690

Answers (2)

DonMag
DonMag

Reputation: 77690

Here:

    } else {
        let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionSingleChoiceStructureCellID", for: indexPath) as! SingleChoiceCell
        //cell.singleChoiceLabel.text = questStruct?.question
        cell.selectionStyle = UITableViewCellSelectionStyle.none
        return cell
    }

You need to "reset" the cell in case it's being reused. Options are:

  1. write a reset() function in the cell, to clear any assigned data and display "default" content, or

  2. create an empty questStruct and call cell.updateCellData(questStruct: questStruct!, indexInTable: indexPath.row)

Option 1. is probably the easiest and most straight-forward.

Upvotes: 5

Jake
Jake

Reputation: 113

Are you sure the data isn't actually duplicated in the questStruct array? If that's not the case then all I can think is that it looks like you have two places where a single choice cell is used. In one of them you set a bunch of data, while in the other one you don't seem to set any data. I'm talking about that last else statement where you have the part where you set singleChoiceLabel.text except it's commented out. If that condition gets hit and it's reusing a cell that was configured for the other singleChoiceStructure branch of the if condition then the information will still be filled out from the previous configuration. It's possible the questionType property of one of your QuestionnaireStructure objects is either spelled incorrectly or just a value you haven't accounted for, which is causing the if statement to hit the else which returns an unconfigured QuestionSingleChoice cell that might still have information from the last time it was used.

Upvotes: 2

Related Questions