You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UITableView单元格复用导致问卷选项联动异常求助

解决UITableView单元格复用导致的问卷选项选中状态混乱问题

这是UITableView复用机制引发的经典问题——你目前只在按钮点击时修改了UI状态,但没有把选中状态和你的Question数据模型绑定起来,再加上cell复用的特性,就会出现“选中第一题,第五题也跟着选中”的情况。

问题根源分析

UITableView的cell是复用的,当第一题的cell滚出屏幕后,会被回收复用给第五题。你之前的做法是在按钮点击时直接改按钮图片,但没有把这个选中状态保存到对应的Question对象里;虽然你在prepareForReuse里重置了按钮状态,但setQuestion方法并没有根据当前question的实际选中状态去更新UI,导致复用后的cell要么保留了之前的状态,要么被重置后无法恢复用户之前的选择,最终出现状态混乱。

解决方案:将UI状态与数据模型绑定

我们需要让Question模型记录用户的选中选项,每次cell复用的时候,根据模型的状态来渲染按钮的图片,同时在按钮点击时更新模型的状态,保证数据和UI同步。

步骤1:修改Question模型,添加选中状态属性

给你的Question结构体/类增加一个属性,用来记录用户选中的选项(比如用1、2、3对应三个选项,nil表示未选中):

struct Question {
    // 保留你原来的属性,比如问题文本、选项内容等
    var selectedAnswer: Int? // 1=选项1,2=选项2,3=选项3,nil代表未选中
}

步骤2:更新ChoicesCell的setQuestion方法

让这个方法根据传入的question的selectedAnswer来设置按钮图片,确保每次cell复用或数据更新时,UI都能正确反映模型状态:

func setQuestion(question: Question) {
    // 先设置问题文本、选项文本等原有内容
    
    let selectedImage = #imageLiteral(resourceName: "ElipseSelected")
    let normalImage = #imageLiteral(resourceName: "Elipse")
    
    switch question.selectedAnswer {
    case 1:
        answerOneButton.setImage(selectedImage, for: .normal)
        answerTwoButton.setImage(normalImage, for: .normal)
        answerThreeButton.setImage(normalImage, for: .normal)
    case 2:
        answerOneButton.setImage(normalImage, for: .normal)
        answerTwoButton.setImage(selectedImage, for: .normal)
        answerThreeButton.setImage(normalImage, for: .normal)
    case 3:
        answerOneButton.setImage(normalImage, for: .normal)
        answerTwoButton.setImage(normalImage, for: .normal)
        answerThreeButton.setImage(selectedImage, for: .normal)
    default:
        // 未选中任何选项时,全部显示正常图片
        answerOneButton.setImage(normalImage, for: .normal)
        answerTwoButton.setImage(normalImage, for: .normal)
        answerThreeButton.setImage(normalImage, for: .normal)
    }
}

步骤3:调整按钮点击逻辑,同步更新数据模型

在按钮点击时,不仅要修改UI,还要更新对应Question的selectedAnswer属性,保证数据和UI一致。可以给ChoicesCell添加一个question引用和indexPath属性,方便更新数据源:

// 在ChoicesCell中添加属性
var question: Question?
var indexPath: IndexPath?

// 修改按钮点击事件
@IBAction func answerOneTapped(_ sender: UIButton) {
    question?.selectedAnswer = 1
    setQuestion(question: question!) // 重新调用setQuestion统一更新UI
    delegate?.didTapAnswerOne(at: indexPath!) // 如果需要通知ViewController,可以传递indexPath
}

@IBAction func answerTwoTapped(_ sender: UIButton) {
    question?.selectedAnswer = 2
    setQuestion(question: question!)
    delegate?.didTapAnswerTwo(at: indexPath!)
}

@IBAction func answerThreeTapped(_ sender: UIButton) {
    question?.selectedAnswer = 3
    setQuestion(question: question!)
    delegate?.didTapAnswerThree(at: indexPath!)
}

步骤4:在ViewController的cellForRowAt中传递必要数据

确保给每个cell设置对应的question和indexPath,让cell能正确关联到数据源:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let question = questions[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: "choicesCell") as! ChoicesCell
    cell.question = question
    cell.indexPath = indexPath
    cell.setQuestion(question: question)
    cell.selectionStyle = .none
    return cell
}

为什么之前的方法无效?

  • 你调用questions.removeAll()是清空数据源,这显然不是解决复用问题的正确方式;
  • prepareForReuse虽然能重置按钮状态,但如果setQuestion没有根据模型的选中状态去渲染UI,那么当用户之前已经选中过某个问题的选项时,cell复用后无法恢复正确的选中状态,反而会因为复用机制导致其他cell的状态混乱。

通过将UI状态与数据模型绑定,我们就能彻底解决复用带来的状态同步问题——不管cell怎么被复用,只要数据模型是正确的,UI就会始终显示正确的状态。

内容的提问来源于stack exchange,提问作者Jessica Kimble

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:42:22