sergey_s
sergey_s

Reputation: 143

TableView cells becomes inactive

I am using a tableView to take some surveys.

Header I use for a question. Footer for «back» and «next» buttons. And tableView cells for answer options. Now I started to have a problem, with some user interaction: when you simultaneously click on the “next” button and select an answer, the answer options cease to be active, nothing can be selected. Although the buttons remain active.

Tell me in what direction to look for the problem and how you can debug this problem in order to understand what's wrong.

It all started after fixing bugs, when the application crashed when simultaneously (or almost) pressing the "next" button and choosing an answer. Because the didSelectRowAt method worked after I changed the current array of answer options, and the selected index in the previous question turned out to be larger than the size of the array with the answers to the new question.

class AssessmentVC: UIViewController {
    @IBOutlet weak var tableView: UITableView!
    var footer: FooterTableView?
    var header: UIView?
    
    var arrayAssessmnet = [AssessmentDM]()
    var assessment: AssessmentDM!
    var question: QuestionDM!
    var viewSeperationHeader = UIView()
    var arrayOptions: [Option]?
    
    var countAssessment = 0
    var numberAssessment = 0
    var numberQuestion = 0
    var countQuestion = 0
    var numberQusttionForLabel = 1
    
    var arrayQuestion = [QuestionDM]()
    var arrayAnswers = [AnswerDM]()
    var arrayEvents = [EventDM]()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        settingAssessment()
    }
    
    
    //MARK: - settingAssessment()
    private func settingAssessment() {
        let id = self.assessment.serverId
        arrayQuestion = QuestionDM.getQuestions(id: id)
        
        assessmentName.text = assessment.name
        countQuestion = arrayQuestion.count
        
        let day = self.assessment.day
        arrayAnswers = AnswerDM.getAnswers(idAssessment: id, day: day)
        
        settingQuestion(eventType: .start)
    }
    
    //MARK: - settingQuestion()
    private func settingQuestion(eventType: EventType? = nil) {
        let prevQuestion = question
        question = arrayQuestion[numberQuestion]
        
        timeQuestion = 0
        
        footer!.grayNextButton()
        //first question
        if numberQuestion == 0 && numberAssessment == 0 {
            footer!.previousButton.isHidden = true
        } else {
            footer!.previousButton.isHidden = false
        }
        
        arrayOptions = [Option]()
        let sortOption = question.options!.sorted {$0.numberOption < $1.numberOption}
        for option in sortOption {
            arrayOptions?.append(Option(label: option.label, value: option.value))
        }

        
        tableView.rowHeight = UITableView.automaticDimension
        tableView.reloadData()
        heightTableView()
        tableView.setContentOffset(.zero, animated: false)
        
    }
    
    //MARK: - heightTableView()
    func heightTableView() {
    }
    
    //MARK: - UITableViewDataSource
    extension AssessmentVC: UITableViewDataSource {
        
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            viewSeperationHeader.isHidden = false
            footer?.viewSeperationFooter.isHidden = false
            tableView.separatorStyle = .singleLine
            return question.options?.count ?? 0
        }
        
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(forIndexPath: indexPath as IndexPath) as AnswerAssessmentCell
            cell.initCell(text: arrayOptions![indexPath.row].label, value: arrayOptions![indexPath.row].value, arrayValue: arrayAnswers[numberQuestion].response, isCheckbox: true)
            return cell
        }
    }
    
    //MARK: - UITableViewDelegate
    extension AssessmentVC: UITableViewDelegate {
        
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            isChangAnswerInAssessment = true
            if question.answerType == "Radio" || question.answerType == "Checkbox"{
                selectRadioOrChekbox(indexPath: indexPath)
            }
        }
        
    }
    
    //MARK: - selectRadioOrChekbox
    extension AssessmentVC {
        private func selectRadioOrChekbox(indexPath: IndexPath) {
            
            if question.answerType == "Radio" {
                
                let cells = tableView.visibleCells as! Array<AnswerAssessmentCell>
                for cell in cells {
                    cell.select = false
                    cell.isSelected = false
                }
                
                let cell = tableView.cellForRow(at: indexPath) as! AnswerAssessmentCell
                cell.select = true
                cell.isSelected = true
                if arrayOptions?.count ?? 0 > indexPath.row {
                    arrayAnswers[numberQuestion].response = arrayOptions![indexPath.row].value
                    footer?.greenNextButton()
                }
            }
            
            if question.answerType == "Checkbox" {
                
                if arrayOptions?.count ?? 0 > indexPath.row {
                    
                    //если нажато что-то, что должно сбросить "None"
                    //                question.options![0].isSelect = false
                    let cells = tableView.visibleCells as! Array<AnswerAssessmentCell>
                    if cells[0].answerLabel.text == "None" {
                        cells[0].select = false
                        cells[0].isSelected = false
                    }
                    var array = arrayAnswers[numberQuestion].response?.components(separatedBy: ";")
                    array?.removeAll { $0 == "0"}
                    if array?.count == 0 {
                        arrayAnswers[numberQuestion].response = nil
                    } else {
                        arrayAnswers[numberQuestion].response = array?.joined(separator: ";")
                    }
                    
                    
                    let cell = tableView.cellForRow(at: indexPath) as! AnswerAssessmentCell
                    cell.select = !cell.select
                    
                    cell.isSelected = cell.select
                    
                    
                    arrayAnswers[numberQuestion].response = array.joined(separator: ";")
                    
                    if array.count == 0 {
                        arrayAnswers[numberQuestion].response = nil
                        footer?.grayNextButton()
                    } else {
                        footer?.greenNextButton()
                    }
                }
            }
        }
    
}


//MARK: - Navigation between questions
extension AssessmentVC {
    func nextQuestion() {
        
        footer!.grayNextButton()
        numberQuestion += 1
        numberQusttionForLabel += 1
        settingQuestion(eventType: .next)
    } else {
    }
    
    func previousQuestion() {
        numberQusttionForLabel -= 1
        settingQuestion(eventType: .previous)
    }
}

Upvotes: 0

Views: 130

Answers (1)

Ptit Xav
Ptit Xav

Reputation: 3219

Some snippets that can help you :

// Answer type : use enum . Here the Strong/Codable is if you want to
// save using JSON encoding/decoding
enum AnswerType: String, Codable {
    case checkBox = "CheckBox"
    case radio  = "Radio"
}

Setup of your cell :

class AnswerAssessmentCell: UITableViewCell {
    ...
    
    // work with Option type
    func initCell(option: Option, response: String?, answerType: AnswerType) {
        // setup cell contents (labels)
        
        // check for selected status
        switch answerType {
            case .checkBox:
                // check if option is in response
                // set isSelected according
                break
            case .radio:
                // check if option is response
                // set isSelected according
                break
        }
    }
}

In table view data source :

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! AnswerAssessmentCell
        // Use the option to init the cell
        // this will also set the selected state
        let optionNumber = indexPath.row
        cell.initCell(option: arrayOptions![optionNumber], response: arrayAnswers[numberQuestion].response, answerType: question.answerType)
        
        return cell
    }

In Table view delegate :

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        isChangAnswerInAssessment = true
        let optionNumber = indexPath.row
        switch question.answerType {
            case .radio:
                selectRadio(optionNumber: optionNumber)
            case .checkBox:
                selectCheckBox(optionNumber: optionNumber)
        }
        // Reload tableview to show changes
        tableView.reloadData()
    }

    // Separate in 2 function for smaller functions 
    // in this function work only with model data, the reload data will do 
    // cell update
    // only the footer view button cooler may need to be changed
    private func selectRadio(optionNumber: Int) {
        // Reset current response
        // set response to optionNumber
        // update footer button cooler if necessary
    }
    private func selectCheckBox(optionNumber: Int) {
        // if option is in response
            // remove option from response
        // else
            // add response to option
        // update footer button cooler if necessary
    }

Hope this can help you

Upvotes: 1

Related Questions