You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS TableView获取屏幕外不可见单元格数据返回nil的解决咨询

解决TableView获取屏幕外单元格数据为nil的问题

问题本质

UITableView.cellForRow(at:) 只能拿到当前在屏幕上可见的单元格,屏幕外的单元格会被系统回收复用,所以调用这个方法会返回nil——你现在的问题就是因为直接从单元格读取数据,而非从数据源拿。正确的做法是用数据驱动UI,让用户输入的内容实时同步到数据源,提交时直接从数据源取数据。

具体解决方案

1. 定义数据源模型

先做一个能存储所有单元格输入数据的模型,把每个类型的答案都对应上:

enum SurveyCellType {
    case yesNoCell, textWithCheckBoxesCell, textWithRadioBtnsCell, ratingCell, ratingWithTextBoxCell, appTextBoxCell, none
}

struct SurveyItem {
    let question: String?
    let cellType: SurveyCellType
    // 对应各单元格的输入数据
    var yesNoAnswer: String?
    var checkboxAnswer: String?
    var radioAnswer: String?
    var ratingText: String?
    var ratingWithText: (rating: String?, text: String?)?
    var textboxAnswer: String?
}

把你原有的eachIndexInfo数组改成[SurveyItem]类型,作为TableView的数据源。

2. 给单元格加回调,同步输入到数据源

每个自定义单元格里加个回调闭包,用户输入内容时,把数据同步回数据源。以YesNoTableViewCell为例:

class YesNoTableViewCell: UITableViewCell {
    var savedFlagValue: String?
    // 输入变化时的回调
    var onAnswerChanged: ((String?) -> Void)?
    
    // 比如用户点了Yes/No按钮时调用这个方法
    func selectAnswer(_ answer: String) {
        savedFlagValue = answer
        onAnswerChanged?(answer)
    }
}

其他类型单元格同理,比如单选按钮单元格:

class TextWithRadioButtonsTableViewCell: UITableViewCell {
    var selectedOption: String?
    var onOptionSelected: ((String?) -> Void)?
    
    func optionTapped(_ option: String) {
        selectedOption = option
        onOptionSelected?(option)
    }
}

3. 配置单元格时绑定回调

在tableView(_:cellForRowAt:)里,给每个单元格设置回调,把用户输入实时存到数据源:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let item = eachIndexInfo[indexPath.row]
    switch item.cellType {
    case .yesNoCell:
        let cell = tableView.dequeueReusableCell(withIdentifier: "YesNoCell", for: indexPath) as! YesNoTableViewCell
        // 初始化显示已保存的答案
        cell.savedFlagValue = item.yesNoAnswer
        // 绑定回调,同步数据到数据源
        cell.onAnswerChanged = { [weak self] answer in
            guard let self = self else { return }
            self.eachIndexInfo[indexPath.row].yesNoAnswer = answer
        }
        return cell
    case .textWithRadioBtnsCell:
        let cell = tableView.dequeueReusableCell(withIdentifier: "RadioCell", for: indexPath) as! TextWithRadioButtonsTableViewCell
        cell.selectedOption = item.radioAnswer
        cell.onOptionSelected = { [weak self] option in
            guard let self = self else { return }
            self.eachIndexInfo[indexPath.row].radioAnswer = option
        }
        return cell
    // 剩下的单元格类型都按这个逻辑处理
    default:
        return UITableViewCell()
    }
}

4. 提交时直接从数据源验证、取数据

修改fetchSelectedCellsInfo,不再从单元格拿数据,直接遍历数据源:

func fetchSelectedCellsInfo() -> [[String: String]]? {
    var result = [[String: String]]()
    
    for item in eachIndexInfo {
        guard let question = item.question else { continue }
        
        switch item.cellType {
        case .yesNoCell:
            guard let answer = item.yesNoAnswer, !answer.isEmpty else {
                showBasicAlert(title: "Please provide feedback for \(question)", message: "")
                return nil // 验证不通过,直接返回
            }
            result.append(["yesNoCell.savedFlagValue": answer])
            
        case .textWithCheckBoxesCell:
            guard let answer = item.checkboxAnswer, !answer.isEmpty else {
                showBasicAlert(title: "Please provide feedback for \(question)", message: "")
                return nil
            }
            result.append(["savedFlagValue": answer])
            
        case .ratingWithTextBoxCell:
            guard let (rating, text) = item.ratingWithText, !rating.isEmpty, !text.isEmpty else {
                showBasicAlert(title: "Please provide feedback for \(question)", message: "")
                return nil
            }
            result.append(["savedFlagValue": rating, "textboxValue": text])
            
        // 其他类型单元格的验证和数据读取逻辑同上
        default:
            continue
        }
    }
    
    return result
}

然后修改提交按钮的逻辑:

@IBAction func submitBtnAction(_ sender: Any) {
    guard let data = fetchSelectedCellsInfo() else {
        // 已经弹出提示,无需额外操作
        return
    }
    // 这里调用API传递data
}

额外提醒

你原代码里混用了appSurveyTableview和myTableview,要确保操作的是同一个TableView实例,避免不必要的错误。

内容的提问来源于stack exchange,提问作者Anilkumar iOS Developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 02:05:24