同一UIViewController配置两个UITableView,同时调用reloadData报空解包错误
问题核心根源
你的崩溃是由几个明显的配置错误导致的:
- UITableView 的数据源、代理方法签名是系统固定的,不存在以
tableView1(...)开头的回调方法,你写的所有自定义命名的表格回调方法系统永远不会触发。两个表格绑定当前控制器作为代理后,所有的回调都会统一走系统约定的、以tableView(_:...)开头的方法,完全无法区分当前回调属于哪个表格。 - 没有在现有数据源方法里做表格实例的区分判断,导致两个表格都在拿第一份数据源(numberRecordList)渲染:既会出现复用单元格时标识匹配错误触发强制解包崩溃,也会出现数据越界访问的nil问题。之前单独重载某一个表格时可以正常运行,是因为另一个表格没有触发重载流程,系统不会向它请求数据;当两个表格同时重载时,两个表格都会走到同一个
tableView(_:...)方法里,强行拿第一个表格的单元格标识去第二个表格里复用,自然会触发解包nil的错误。 - 附带代码笔误:原第二个数据源方法中定义的是
countFinanceRecordList,判断时却引用了不存在的countSettingRecordList,因为这个方法从来没被系统调用,所以编译阶段没有暴露这个错误。
具体修复步骤
- 彻底删除所有以
tableView1(...)开头的自定义方法,所有表格的数据源、代理逻辑全部统一写在系统约定的tableView(_:...)签名方法中。 - 在每个数据源、代理方法内部,通过方法传入的
tableView参数和你控制器持有的两个表格实例做比对,分别返回对应表格需要的数据、配置。 - 将所有*强制解包单元格的
as!*替换为安全解包逻辑,避免单元格复用失败直接触发nil崩溃。
修复后的核心代码参考
// 控制器中持有的两个表格实例 private let numberRecordTableView = UITableView() private let settingRecordTableView = UITableView() // 统一的数据源方法:返回对应表格的行数 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if tableView == numberRecordTableView { return JSON_VDICheckFull.response?.dataItems?.numberRecordList?.count ?? 0 } else if tableView == settingRecordTableView { return JSON_VDICheckFull.response?.dataItems?.settingRecordList?.count ?? 0 } return 0 } // 统一的估算行高方法 func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { if tableView == numberRecordTableView { return 30.0 } else { return 110.0 } } // 统一的单元格配置方法 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // 配置第一个表格的单元格 if tableView == numberRecordTableView { guard let cell = tableView.dequeueReusableCell(withIdentifier: "NumberRecordListCell", for: indexPath) as? NumberRecordListCell else { return UITableViewCell() } cell.setNeedsLayout() cell.layoutIfNeeded() cell.fieldDate.text = JSON_VDICheckFull.response?.dataItems?.numberRecordList?[indexPath.row].dateOfInformation ?? "---" cell.fieldSource.text = JSON_VDICheckFull.response?.dataItems?.numberRecordList?[indexPath.row].sourceOfInformation ?? "---" cell.fieldNumber.text = String(JSON_VDICheckFull.response?.dataItems?.numberRecordList?[indexPath.row].number ?? 0) cell.separatorInset = UIEdgeInsets.zero cell.layoutMargins = UIEdgeInsets.zero return cell } // 配置第二个表格的单元格 guard let cell = tableView.dequeueReusableCell(withIdentifier: "SettingRecordListCell", for: indexPath) as? SettingRecordListCell else { return UITableViewCell() } cell.setNeedsLayout() cell.layoutIfNeeded() return cell }
注意事项
- 请确保两个表格在初始化时,分别注册了对应的单元格复用标识:
numberRecordTableView.register(NumberRecordListCell.self, forCellReuseIdentifier: "NumberRecordListCell")、settingRecordTableView.register(SettingRecordListCell.self, forCellReuseIdentifier: "SettingRecordListCell"),避免复用单元格时返回nil。 - 两个表格分别设置代理、数据源为当前控制器后,直接调用
numberRecordTableView.reloadData()和settingRecordTableView.reloadData()即可正常触发对应的数据回调,不会再出现解包nil的崩溃。
内容的提问来源于stack exchange,提问作者opticalbot
相关产品推荐
相关产品推荐

