Search code examples
iosiphoneswiftuitableviewswift4

Not Recognizing Clicked Cell UITableView inside UITableViewCell using NIB


I'm writing an app that have a dashboard with multiple cells. One of the cells have a question, but the answer are dynamically filled, so I decided to use a UITableView to handle it.

I set the the UITableViewCell as the delegate and dataSource of the internal UITableView and made the configurations for define the cell and the selected state.

extension SurveyTableViewCell: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        answers = model.getSurveyAnswers()
    
        return (answers?.count)!
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier, for: indexPath) as! InsideSurveyTableViewCell
    
        cell.idAnswer.text = alphabetQuestion[indexPath.row]
        cell.answer.text = answers?[indexPath.row]
    
        return cell
    }

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100.0
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier, for: indexPath) as! InsideSurveyTableViewCell
    
        cell.selectRow()
    }

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier, for: indexPath) as! InsideSurveyTableViewCell
    
        cell.deselectRow()
    }
}

But the click inside the cell in the internal UITableViewCell is not recognized. I need to recognize this click to after send the user answer to the server.

I saw some solutions, but using storyboard. I use only nib's on my projects.

But I still tried with an approach that I saw on YouTube which uses storyboard.

On the cell that will use the internal UITableView I declared a function to set the delegate and dataSource of the internal tableView and gave to it a tag.

extension SurveyTableViewCell {

    func setTableViewDataSourceDelegate<D:UITableViewDelegate & UITableViewDataSource>(_ dataSourceDelegate: D, forRow row: Int) {
        subTableView.dataSource = dataSourceDelegate
        subTableView.delegate = dataSourceDelegate
    
        subTableView.reloadData()
    }
}

Than on the viewController that manage the outer UITableView:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        if tableView.tag == 1 {
            let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier) as! InsideSurveyTableViewCell
        
            cell.idAnswer.text = "A."
            cell.answer.text = "QUALQUER COISA"
        
            return cell
        }

        if retrivedCell is SurveyTableViewCell {
            
            let cell = tableView.dequeueReusableCell(withIdentifier: SurveyTableViewCell.identifier, for: indexPath) as! SurveyTableViewCell
            cell.delegate = self
            
            cell.setTableViewDataSourceDelegate(self, forRow: indexPath.row)
            
            cell.setPositionRow(row: indexPath.row - 1)
            cell.subTableView.rowHeight = UITableViewAutomaticDimension
            cell.subTableView.estimatedRowHeight = 50
            
            return cell
        }
 }


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
        if tableView.tag == 1 {
            return 3
        }
    
        var numberOfCells: Int = 0
    
        if cellsToPresent != nil {
            numberOfCells = cellsToPresent!.count
        }
    
        return numberOfCells + 1
 }

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
    if tableView.tag == 1 {
        let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier) as! InsideSurveyTableViewCell
        
        cell.selectRow()
    }
}

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    
    if tableView.tag == 1 {
        let cell = tableView.dequeueReusableCell(withIdentifier: InsideSurveyTableViewCell.identifier) as! InsideSurveyTableViewCell
        
        cell.deselectRow()
    }
}

The selectRow and deselectRow are methods to change the label of the cell of the inner tableView.

But still without success.

if I use the method:

tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)

The app break complaining that I'm trying to dequeue different cells with the same indexPath.

Thanks for your help.


Solution

  • Don't use let cell = tableView.dequeueReusableCell(withIdentifier:) in didSelect or didDeSelect methods.

    Use

    let cell = tableView.cellForRow(at: indexPath)
    

    I hope this will help you.