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

UITableView点击didSelectRow提示NSArray空数组下标越界如何解决?

问题根因确认

你提到的「数据源已修改、UI未完成刷新时用户点击」的场景确实存在:
[tableView reloadData] 本质是给UITableView打上待刷新标记,不会同步立即执行cell刷新、行数/section数更新的逻辑,需要等到当前Runloop周期结束才会真正执行刷新操作。你在修改数据源之后、Runloop结束前的这段间隙里,界面展示的还是旧数据对应的索引,若此时用户点击,indexPath 是旧数据的索引,而数据源已经更新为新数据,当新数据源的行数小于旧索引的row值时,就会触发数组越界崩溃,符合你描述的低概率复现特征。

解决方案

可根据业务场景选择以下一种或多种组合方案:

  • 访问数据源前增加边界校验(最优先通用方案)
    所有需要通过indexPath访问数据源的位置(包括didSelectRow、cell渲染方法等),都先判断索引是否在数据源合法范围内,避免越界:
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        // 先校验边界,非法索引直接返回
        if (indexPath.section >= [self numberOfSectionsInTableView:tableView] 
            || indexPath.row >= [self tableView:tableView numberOfRowsInSection:indexPath.section]) {
            return;
        }
        id item = [self.datasource objectAtIndex:indexPath.row];
        // 后续业务逻辑
    }
    
  • 调整数据源更新时机,缩短风险间隙
    把数据源赋值逻辑从方法开头移到reloadData调用的紧前面,减少数据源修改到触发刷新的间隔时间,降低用户点击的概率:
    - (void)reloadContent {
        NSArray *newItems = [self getCurrentItems];
        // 先执行所有计算、frame调整、表头设置等非数据源修改逻辑
        <Do some Calculations and set tableView frame and other stuff> 
        // 最后再更新数据源,紧接着触发刷新
        self.datasource = newItems;
        [self.tableView reloadData];
    }
    
  • 刷新过程中临时禁用交互
    如果计算逻辑耗时较长,可以在刷新周期内禁用tableView的点击交互,刷新完成后再恢复,可通过CATransaction捕获reloadData的完成回调:
    - (void)reloadContent {
        self.tableView.userInteractionEnabled = NO;
        NSArray *newItems = [self getCurrentItems];
        <Do some Calculations and set tableView frame and other stuff> 
    
        [CATransaction begin];
        [CATransaction setCompletionBlock:^{
            // 刷新完成后恢复交互
            self.tableView.userInteractionEnabled = YES;
        }];
        self.datasource = newItems;
        [self.tableView reloadData];
        [CATransaction commit];
    }
    
  • 用差异更新代替全量reloadData
    如果能拿到新旧数据源的差异(新增/删除/修改的索引),使用insertRowsAtIndexPaths:withRowAnimation:、deleteRowsAtIndexPaths:withRowAnimation:、reloadRowsAtIndexPaths:withRowAnimation:等方法做局部更新,系统会自动保证索引和数据源的一致性,比全量刷新安全性更高,性能也更好。

额外注意:所有对datasource的读写操作、UI相关操作必须保证全部在主线程执行,子线程修改datasource也会触发多线程安全导致的同类崩溃。

内容的提问来源于stack exchange,提问作者Sandeep

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 04:24:05