UITableView单元格正在重用/重复

时间:2019-09-19 14:32:49

标签: ios swift uitableview

我知道有很多与我的问题类似的问题,但是其中许多已经过时,还有其他问题与我的案子无关。

我在UITableView中有一个问卷,其中包含5个问题,每个问题有3个选择。 选择是一个UIButton,单击后可更改图像。 但是,当第一个问题得到回答时,第五个问题也将得到回答!

这是我的tableView方法:

    var questions: [Question] = []

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return questions.count
    }

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

        cell.setQuestion(question: question)
        cell.selectionStyle = .none
        return cell
    }

这是在选择按钮时将图像设置到选择按钮的方式:

    @IBAction func answerOneTapped(_ sender: UIButton) {
    delegate?.didTapAnswerOne()
    print("answerOneTapped")
    answerOneButton.setImage(#imageLiteral(resourceName: "ElipseSelected"), for: .normal)
    answerTwoButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
    answerThreeButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
}

@IBAction func answerTwoTapped(_ sender: UIButton) {
    delegate?.didTapAnswerTwo()
    print("answerTwoTapped")
    answerOneButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
    answerTwoButton.setImage(#imageLiteral(resourceName: "ElipseSelected"), for: .normal)
    answerThreeButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
}

@IBAction func answerThreeTapped(_ sender: UIButton) {
    delegate?.didTapAnswerThree()
    print("answerThreeTapped")
    answerOneButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
    answerTwoButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
    answerThreeButton.setImage(#imageLiteral(resourceName: "ElipseSelected"), for: .normal)
}

我尝试了几种没有运气的解决方案,例如:

questions.removeAll()

cellForRowAtViewWillAppear

我还尝试将按钮设置为以下未选择的选项:

    override func prepareForReuse() {
    super.prepareForReuse()
    answerOneButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
    answerTwoButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
    answerThreeButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
}

我已经花了很多时间尝试解决这个问题。并且我阅读了有关dequeueReusableCell的Apple文档,并收集了许多信息,但没有结果...请任何人帮助!

4 个答案:

答案 0 :(得分:2)

问题在于,即使prepareForReuse可以正常工作(奇怪的是,它没有工作),当您不需要它时,它也会重用您的第一个单元格。 我一直使用的最佳解决方案是将单元格状态保存在委托中,并在tableView(_:cellForRowAt :)中重置它们

例如:

在您的情况下,您可以将3个案例添加到Question类属性selecteddAnswer并枚举

set JPDA_OPTS=-agentlib:jdwp=transport=dt_socket,address=8082,server=y,suspend=n

在您的cell.setQuestion(question :)函数更新按钮的图像中。像这样的东西:

enum answer {
    case one
    case two
    case three
}

var choosedAnswer: answer?

并且不要忘记在选择按钮后更新[问题]数组中的模型

    switch question.choosedAnswer {
    case .one:
        answerOneButton.setImage(#imageLiteral(resourceName: "ElipseSelected"), for: .normal)
        answerTwoButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
        answerThreeButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
    case .two:
        answerOneButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
        answerTwoButton.setImage(#imageLiteral(resourceName: "ElipseSelected"), for: .normal)
        answerThreeButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
    case .three:
        answerOneButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
        answerTwoButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
        answerThreeButton.setImage(#imageLiteral(resourceName: "ElipseSelected"), for: .normal)
    default:
        answerOneButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
        answerTwoButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
        answerThreeButton.setImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
    }

在您的单元格委托中,点击功能发送自我:

func didTapAnswerOne(cell: UITableViewCell) {
    guard let indexPath = tableView.indexPath(for: sender) else {return}
    questions[indexPath.row] = questions[indexPath.row] == .one ? nil : .one
}

func didTapAnswerTwo(cell: UITableViewCell) {
    guard let indexPath = tableView.indexPath(for: sender) else {return}
    questions[indexPath.row] = questions[indexPath.row] == .two ? nil : .two
}

func didTapAnswerThree(cell: UITableViewCell) {
    guard let indexPath = tableView.indexPath(for: sender) else {return}
    questions[indexPath.row] = questions[indexPath.row] == .three ? nil : .three
}

答案 1 :(得分:0)

具有tableView实例的UIViewController应该知道所有已更改的状态。

我的意思是:

类似这样的事情。您可以创建对象来实现类似的目的

[Question 1] --> [State of Answer1, state of Answer2, state of Answer3]
[Question 2] --> [State of Answer1, state of Answer2, state of Answer3]
[Question 3] --> [State of Answer1, state of Answer2, state of Answer3]
so forth..

例如:

初始状态:

Question 1 -> (False, False, False)

如果用户单击问题1的答案2,则:

Question 1 -> (False, True, False)

然后在cellForItem

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


.
.
 (question[index.row].isTapped[answer])?
 cell.answerOneButtonsetImage(#imageLiteral(resourceName: "ElipseSelected"), for:   .normal) 
 :cell.answerOneButtonsetImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
.

}

答案 2 :(得分:0)

Apple documentation prepareForReuse() ...

  

出于性能原因,您应该仅重置单元格的属性   与内容无关的内容,例如Alpha,编辑和   选择状态。表格视图的委托在   tableView(_:cellForRowAt :)应该始终在重置所有内容时   重用单元格。如果单元格对象没有关联的重用   标识符,则不会调用此方法。

此摘录中最重要的一点...

tableView(_:cellForRowAt:)中的表视图的委托在重用单元格时应始终重置所有内容。

我的建议是重置tableView(_:cellForRowAt:)中的内容。

例如...

cell.answerOneButton.setImage(UIImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
cell.answerTwoButton.setImage(UIImage(#imageLiteral(resourceName: "Elipse"), for: .normal)
cell.answerThreeButton.setImage(UIImage(#imageLiteral(resourceName: "Elipse"), for: .normal)

请原谅我,虽然这听起来是居高临下的(不是故意的),但它将有助于将模型和视图视为独立的。视图不知道模型的(选择)状态,并且模型不管理视图。表格视图控制器是两者之间的通信器(控制器)。

因此,也许第五个单元格未更改模型中第五个问题的答案,而是视图仅根据控制器中的代码指令更改了其在屏幕上的显示。在加载和/或重新加载表视图时,可能值得使用断点和/或到终端的print()检查模型值。

答案 3 :(得分:-1)

尝试与dequeueReusableCell(withIdentifier:for:) https://developer.apple.com/documentation/uikit/uitableview/1614878-dequeuereusablecell一起使用出队

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

    cell.setQuestion(question: question)
    cell.selectionStyle = .none
    return cell
}