解决RxDataSources中“Requested the number of rows for section (-1)”崩溃问题
问题解决方案
针对你遇到的RxTableViewSectionedReloadDataSource结合UITableView时的崩溃问题,以下是具体的解决思路和代码实现:
核心崩溃原因
该崩溃本质是UITableView内部状态与数据源不一致,当数据源为空或快速更新时,UITableView可能尝试访问索引为-1的分区(超出合法范围),触发系统断言。
具体解决步骤
1. 强制保证数据源分区数组非空
当原始数据为空时,返回一个包含空items的占位分区,彻底避免UITableView处理空分区数组的边界异常:
// 假设你的分区模型为CustomSection func convertToSections(from rawData: [YourItemModel]) -> [CustomSection] { guard !rawData.isEmpty else { // 返回占位分区,模型和样式可根据需求调整 return [CustomSection(headerTitle: "", items: [])] } // 正常的分区转换逻辑 return yourNormalSectionTransformLogic(rawData) }
2. 过滤重复/频繁的数据源更新
针对用户快速点击标签的场景,用RxSwift操作符过滤无效更新,避免UITableView状态混乱:
// 假设你的数据源Observable为dataStream dataStream // 过滤完全相同的数据源更新,避免重复刷新 .distinctUntilChanged { oldSections, newSections in guard oldSections.count == newSections.count else { return false } return zip(oldSections, newSections).allSatisfy { $0 == $1 } } // 防抖处理,避免短时间内多次触发更新(300ms可根据需求调整) .debounce(.milliseconds(300), scheduler: MainScheduler.instance) .bind(to: tableView.rx.items(dataSource: yourDataSource)) .disposed(by: disposeBag)
3. 重写数据源的分区/行数校验逻辑
直接在RxTableViewSectionedReloadDataSource中重写分区和行数的计算方法,强制保证索引合法:
let dataSource = RxTableViewSectionedReloadDataSource<CustomSection>( configureCell: { ds, tv, ip, item in // 你的Cell配置逻辑 return yourConfiguredCell } ) // 强制分区数至少为1 dataSource.numberOfSections = { dataSource in max(dataSource.sectionModels.count, 1) } // 确保分区索引永远在合法范围内 dataSource.numberOfRowsInSection = { dataSource, section in let safeSection = max(min(section, dataSource.sectionModels.count - 1), 0) return dataSource.sectionModels[safeSection].items.count }
4. 确保所有UI更新在主线程执行
即使RxSwift默认绑定到主线程,也显式指定线程,避免后台线程更新导致的时序问题:
dataStream .observe(on: MainScheduler.instance) .bind(to: tableView.rx.items(dataSource: yourDataSource)) .disposed(by: disposeBag)
5. 检查自定义UITableView代理方法的边界处理
如果你手动实现了heightForRowAt、viewForHeaderInSection等代理方法,必须添加索引安全校验:
tableView.rx.heightForRowAt .subscribe(onNext: { [weak self] indexPath in guard let self = self, indexPath.section < self.dataSource.sectionModels.count, indexPath.row < self.dataSource.sectionModels[indexPath.section].items.count else { return 44 // 返回默认行高 } // 正常计算行高逻辑 }) .disposed(by: disposeBag)
内容的提问来源于stack exchange,提问作者Oguz Yildirim
相关产品推荐
相关产品推荐

