Swift 3 - 使用多个自定义单元重用单元的问题

Posted

技术标签:

【中文标题】Swift 3 - 使用多个自定义单元重用单元的问题【英文标题】:Swift 3 - Problems in reusing cell with multiple custom cells 【发布时间】:2017-06-16 13:01:20 【问题描述】:

我在 UITableview 中向下滚动时遇到问题。当单元格被重用时,该表向我显示了具有旧内容的单元格。

问题如下:

Swift 想要重用旧单元格,但没有正确清除旧单元格中的旧内容。这会导致单元格包含旧内容,尽管我正在向单元格提供新数据。

UITableView 的架构,如果如下:

每个自定义单元格都有自己的标识符 每个自定义单元格在自己的类中分隔

问题截图:

问卷开始截图

向下滚动的表格

这里的问题是“Handedness”-Cell 显示单元格编号 3(因为单元格的重复使用),这是不对的

numberOfSection-Method

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

numberOfRowsInSection-Method

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

cellForRowAt-方法

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 = s-s-radioButtonsController()
            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
        
    


我检查了什么:

“questStruct”的数据提供最新数据 覆盖“prepareForReuse”-Methode 没有成功

【问题讨论】:

导致问题的单元格标识符是什么? “这里的问题是“惯用手”-Cell ... 这是不对的” 如果不对,那是什么假设要展示吗? @Subramanian 标识符为“QuestionSingleChoiceStructureCellID”的单元格导致了问题。 @Heelow 能否更新cell.updateCellData() 方法的代码 @DonMag 这是数组的内容 Optional("Date of Birth") Optional("Gender") Optional("Handedness") Optional("耳鸣家族史") Optional("如果是") Optional("初始发作:您是什么时候第一次出现耳鸣?") Optional("您是如何感知开始的?") Optional("您的耳鸣的初始发作是否与") Optional("如果其他") 【参考方案1】:

这里:

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

您需要“重置”单元格以防它被重复使用。选项是:

    在单元格中编写reset() 函数,以清除任何分配的数据并显示“默认”内容,或

    创建一个空的questStruct 并调用cell.updateCellData(questStruct: questStruct!, indexInTable: indexPath.row)

选项 1. 可能是最简单和最直接的。

【讨论】:

prepareForReuse() 是放置reset() 内容的位置。 非常感谢! :-) 这是代码中的错误。我很感激你帮助了我【参考方案2】:

您确定数据实际上并未在 questStruct 数组中重复吗?如果不是这种情况,那么我所能想到的就是您似乎有两个使用单个选择单元格的地方。在其中一个中,您设置了一堆数据,而在另一个中,您似乎没有设置任何数据。我说的是最后一个 else 语句,其中你有设置 singleChoiceLabel.text 的部分,但它被注释掉了。如果该条件被满足并且它正在重用为 if 条件的另一个 singleChoiceStructure 分支配置的单元格,则仍将从先前的配置中填写信息。您的 QuestionnaireStructure 对象之一的 questionType 属性可能拼写错误或只是您未考虑的值,这导致 if 语句命中 else ,该 else 返回一个未配置的 QuestionSingleChoice 单元格,该单元格可能仍包含最后一个信息使用时间。

【讨论】:

"你确定 questStruct 数组中的数据实际上没有重复吗?" => 是的,我非常确定。当我打印出 questStruct Array 时,它会显示正确的内容。 并且 questiontype 属性拼写正确,包括每个值的大小写?我也同意 Subramanian:用 updateCellData 的代码更新问题会很有帮助。 "我说的是最后一个 else 语句" => 我怎样才能避免最后一个 "else"?编译器强制我在每种情况下都返回一个单元格 我认为你不需要避免最后一个 else 语句,但如果你想看看这是否是这样做的,你可以只返回 UITableViewCell() 它将返回一个白色单元格并明确发生了什么。真的,虽然你应该在那里设置一个断点,看看它是否会被击中。如果是这样,您就知道您的 questionType 属性很可能存在问题 我认为你是对的!!!! :-) 它会被点击,但我不知道为什么......这可以解释桌子的这种奇怪行为

以上是关于Swift 3 - 使用多个自定义单元重用单元的问题的主要内容,如果未能解决你的问题,请参考以下文章

带有两个自定义单元格的 TableView 导致单元格重用问题(Swift 4)

防止在表格视图Swift中重用自定义单元格

重用自定义 tableView 单元格时重复显示相同的子视图(Swift 4.1)

带有Swift的多个自定义单元格的UITableview

多个自定义 UITableViewCell 相互覆盖 Swift

Swift - uitableview 重用单元格时用户输入混淆?