Ячейки UITableView используются / повторяются - PullRequest
0 голосов
/ 19 сентября 2019

Я знаю, что есть много вопросов, похожих на мои, однако многие из них устарели, а другие не работали с моим делом.

У меня есть анкета в 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()

в cellForRowAt и в ViewWillAppear

Я также пыталсяустановить кнопки на невыбранный выбор в:

    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)
}

Я уже потратил много часов, пытаясь решить эту проблему.и я прочитал документы Apple относительно dequeueReusableCell и собрал много информации безрезультатно ... Пожалуйста, помогите!

Ответы [ 4 ]

2 голосов
/ 19 сентября 2019

Проблема в том, что даже если prepareForReuse будет работать (странно, что это не так), он будет использовать вашу первую ячейку, когда она вам не нужна.Лучшее решение, которое я всегда использую, - это сохранить состояние ячеек в делегате и сбросить их в tableView (_: cellForRowAt:)

Например:

ВВ вашем случае вы можете добавить к свойству класса Question свойство chootedAnswer и перечислить 3 случая

enum answer {
    case one
    case two
    case three
}

var choosedAnswer: answer?

В вашей функции cell.setQuestion (question :) кнопка обновления изображений.Примерно так:

    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)
    }

И не забудьте обновить модели в вашем массиве [Question] после того, как кнопки выберут

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
}

В делегате вашей ячейкинажмите функции отправить себя:

delegate?.didTapAnswerOne(cell: self)
0 голосов
/ 19 сентября 2019

Из документации Apple prepareForReuse() ...

Из соображений производительности следует сбрасывать только те атрибуты ячейки, которые не связаны с содержимым, например:альфа, редактирование и выбор состояния.Делегат табличного представления в 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() для терминала.

0 голосов
/ 19 сентября 2019

Ваш UIViewController, имеющий экземпляр tableView, должен знать все состояние, которое было изменено.

Я имею в виду следующее:

Что-то вроде этого.Вы можете создать объект для достижения чего-то похожего

[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)

Если пользователь нажимает на ответ 2вопроса 1:

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)
.

}
0 голосов
/ 19 сентября 2019

Попробуйте использовать снятие очереди с 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
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...