Данные табличного представления переопределены - PullRequest
0 голосов
/ 02 апреля 2020

У меня есть UITableView. Его ячейка содержит метку, которая будет отображать вопрос, кнопку «да» и кнопку «нет». Цель состоит в том, чтобы просмотреть вопросы один за другим. Сначала я вызываю API для получения вопросов в методе viewDidLoad:

override func viewDidLoad() {
        super.viewDidLoad()
        tableView.allowsSelection = false

        getQuestions(baseComplainID: "1") { (questions, error) in
            self.questions = questions
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
    }

В методе cellForRowAt я отображаю их один за другим:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? TableViewCell else {
            fatalError("Fatal Error")
        }
        cell.yesButton.isHidden = false
        cell.noButton.isHidden = false

        if indexPath.row + 1 == displayNumber {
            cell.questionLabel.text = questions[indexPath.row].question_name
        } else {
            cell.yesButton.isHidden = true
            cell.noButton.isHidden = true
        }

        cell.yesButton.addTarget(self, action: #selector(action), for: .touchUpInside)
        cell.noButton.addTarget(self, action: #selector(action), for: .touchUpInside)

        return cell
    }

, и это выполняемое действие при нажатии «да» или «нет»:

@objc func action(sender: UIButton){
        let indexPath = self.tableView.indexPathForRow(at: sender.convert(CGPoint.zero, to: self.tableView))
        let cell = tableView.cellForRow(at: indexPath!) as? TableViewCell
        cell?.yesButton.isEnabled = false
        cell?.noButton.isEnabled = false

        if sender == cell?.yesButton {
            sender.setTitleColor(.black, for: .normal)
            sender.backgroundColor = .green
        } else {
            sender.setTitleColor(.black, for: .normal)
            sender.backgroundColor = .green
        }

        displayNumber += 1
        self.tableView.reloadData()
    }

Здесь я просто изменяю цвет фона кнопки и увеличиваю номер дисплея, чтобы отобразить следующий вопрос.

Все это прекрасно работает, ЗА ИСКЛЮЧЕНИЕМ прокрутка, данные переопределяются, и иногда я нахожу метку вопроса пустой, и вопросы заменяют друг друга. Я знаю, что это нормально из-за возможности повторного использования ячеек, но я не знаю, как это исправить.

Есть предложения, пожалуйста?

Ответы [ 3 ]

0 голосов
/ 02 апреля 2020

Вам нужно будет следить за тем, что да, нет и ни для каждой ячейки. Я бы прикрепил перечисление к другой структуре данных вместе с вашими вопросами. Ваша основная проблема заключалась в том, что вы только отслеживали свой вопрос. Вы также должны следить за своим ответом. Таким образом, когда вы загружаете ячейку, вы можете настроить каждую кнопку на нужные вам цвета в cellForRow(at:)

struct QuestionAndAnswer {
    enum Answer {
        case yes
        case no
        case nada
    }

    var question: Question
    var answer: Answer
}

и попытаться не перезагружать весь табличный вид при нажатии кнопки. tableView.reloadData () стоит дорого и отвлекает пользователя. Вы должны перезагрузить только строку, которая изменилась при нажатии кнопки.

Добавьте обратные вызовы в вашу ячейку, чтобы вы знали, к какой ячейке принадлежат соответствующие кнопки. Обратите внимание, как в обратных вызовах onYes и onNo мы отслеживаем ваш выбор «да» или «нет», а затем сразу же перезагружаем строку ниже. Когда строка будет перезагружена, мы наконец узнаем, какой цвет сделать кнопкой.

class AnswerCell: UITableViewCell {
    @IBOutlet weak var yesButton: UIButton!
    @IBOutlet weak var noButton: UIButton!

    var onYes: (() -> Void)) = {}
    var onNo: (() -> Void)) = {}
}

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

    // ...

    cell.yesButton.backgroundColor = qAndA.answer == .yes ? .green : .white
    cell.noButton.backgroundColor = qAndA.answer == .no ? .green : .white

    cell.onYes = {
        questionsAndAnswers[indexPath.row].answer = .yes
        tableView.reloadRows(at: [indexPath], with: .fade)
    }
    cell.onNo = {
        questionsAndAnswers[indexPath.row].answer = .no
        tableView.reloadRows(at: [indexPath], with: .fade)
    }

    // ...
}
0 голосов
/ 03 апреля 2020

Итак, предположим, у вас есть 10 вопросов, поэтому очень простое и обходное решение - объявить новый массив, который имеет 10 элементов, как следует

var questionIsLoaded = Array(repeating:true , count 10)

в предыдущей строке будет объявлен массив из 10 элементов в каждом Элемент is bool, который в нашем случае будет true

, затем объявляет функцию, которая обрабатывает, если вопрос загружен или нет следующим образом, поэтому, если вопрос загружен таким образом, вопрос с его indexPath должен быть помечен как true, и в результате кнопки yes и no должны быть скрыты, кнопки должны быть показаны

func handleQuestionIfLoaded(cell:yourCellType, indexPath:IndexPath) {
if questionIsLoaded[indexPath.row] , indexPath.row + 1 == displayNumber { {
questionIsLoaded[indexPath.row] = false
            cell.questionLabel.text = questions[indexPath.row].question_name
            cell.yesButton.isHidden = questionIsLoaded[indexPath.row]
            cell.noButton.isHidden = questionIsLoaded[indexPath.row]
        } else {
            cell.yesButton.isHidden = questionIsLoaded[indexPath.row]
            cell.noButton.isHidden = questionIsLoaded[indexPath.row]
        }

        cell.yesButton.addTarget(self, action: #selector(action), for: .touchUpInside)
        cell.noButton.addTarget(self, action: #selector(action), for: .touchUpInside)
}

, затем замените тело cellForRowAt на приведенную выше функцию, затем свою функцию действия будет выглядеть следующим образом:

@objc func action(sender: UIButton){
        let indexPath = self.tableView.indexPathForRow(at: sender.convert(CGPoint.zero, to: self.tableView))
        let cell = tableView.cellForRow(at: indexPath!) as? TableViewCell
        cell?.yesButton.isEnabled = questionIsLoaded[indexPath.row]
        cell?.noButton.isEnabled = questionIsLoaded[indexPath.row]

    if sender == cell?.yesButton {
        sender.setTitleColor(.black, for: .normal)
        sender.backgroundColor = .green
    } else {
        sender.setTitleColor(.black, for: .normal)
        sender.backgroundColor = .green
    }

    displayNumber += 1
    self.tableView.reloadData()
}

Теперь ваши ячейки зависят от внешней зависимости - массива, который вы объявили ранее, это означает, что когда ячейки снимаются с очереди, они будут повторно использоваться в соответствии с вопросом загружается или нет, сначала запрашивая элемент массива по указанному c indexPath, если элемент равен true или ложь

0 голосов
/ 02 апреля 2020
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? TableViewCell else {
            fatalError("Fatal Error")
        }
        cell.yesButton.isHidden = false
        cell.noButton.isHidden = false

        if indexPath.row + 1 == displayNumber {
            cell.questionLabel.text = questions[indexPath.row].question_name
        } else {
            cell.yesButton.isHidden = true
            cell.noButton.isHidden = true
        }

        cell.yesButton.addTarget(self, action: #selector(action), for: .touchUpInside)
        cell.noButton.addTarget(self, action: #selector(action), for: .touchUpInside)

        return cell
    }

Я чувствую, что ваша проблема заключается здесь в функции cellForRowAt.

у вас есть это написано

if indexPath.row + 1 == displayNumber { your code here }

но я не уверен, зачем вам это нужно.

вы должны делать что-то подобное внутри cellForRowAt

let data = self.questions
data = data[indexPath.row]
cell.questionLabel.text = data.question_name

вы не должны добавлять 1 к вашему indexPath.row

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