如何在静态UITableView中嵌入动态UITableView?解决NSRangeException报错
在一个使用静态单元格的UITableViewController界面中,所有UI组件(标签、图片、按钮等)都放在静态单元格内。现在需要在其中一个静态单元格里嵌入一个高度不固定、行数动态变化的UITableView(tag设为2)。编写的代理与数据源代码如下:
override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if tableView.tag == 2 { return 3 } return super.tableView(tableView, numberOfRowsInSection: section) } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if tableView.tag == 2 { let cell = (tableView.dequeueReusableCell(withIdentifier: Constant.ReuseIdentifiers.offersViewCell) as? OffersTableViewCell)! return cell } return super.tableView(tableView, cellForRowAt: indexPath) } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if tableView.tag == 2 { // Do something when a dynamic row is selected } else { super.tableView(tableView, didSelectRowAt: indexPath) } }
运行应用进入该界面时,抛出错误:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
此前无动态UITableView时无需实现这些方法,问题应该出在代理/数据源方法的区分上,请问如何正确区分静态与动态UITableView的代理/数据源方法,实现该功能?(后续再处理动态表高度自适应)
出现这个错误的核心原因是:你重写了numberOfSections(in:)方法并固定返回1,覆盖了静态表格在Storyboard中的原始分区配置,导致静态表格的数据源逻辑混乱,引发数组越界。正确的做法是仅针对动态子表格处理代理/数据源逻辑,静态表格的所有方法完全交给父类处理,具体修正步骤如下:
删除重写的
numberOfSections(in:)方法
静态表格的分区数由Storyboard中的可视化配置决定,不要通过代码强行覆盖返回固定值,否则会破坏静态表格的原有数据源结构。完善动态表格的代理/数据源区分逻辑
确保所有代理/数据源方法都先判断是否是动态子表格(tag=2),只有符合条件时才自定义处理,否则直接调用父类方法:override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // 仅处理动态子表格,静态表格逻辑交给父类 guard tableView.tag == 2 else { return super.tableView(tableView, numberOfRowsInSection: section) } return 3 // 动态表格的行数,可根据实际数据动态调整 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard tableView.tag == 2 else { return super.tableView(tableView, cellForRowAt: indexPath) } // 用可选绑定替代强制解包,避免cell复用失败时崩溃 guard let cell = tableView.dequeueReusableCell(withIdentifier: Constant.ReuseIdentifiers.offersViewCell, for: indexPath) as? OffersTableViewCell else { return UITableViewCell() } // 在这里配置动态表格cell的内容 return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { guard tableView.tag == 2 else { super.tableView(tableView, didSelectRowAt: indexPath) return } // 动态表格行的选中逻辑 }额外注意事项
- 确保动态子表格的
delegate和dataSource已设置为当前UITableViewController,保证代理方法能被正确回调。 - 不要在静态表格的代理方法中修改其原有配置,静态表格的所有行为依赖Storyboard中的可视化设置,代码层面尽量不要干预。
- 确保动态子表格的
内容的提问来源于stack exchange,提问作者Raj Salla

