Swift使用SkeletonView实现多分区UITableView骨架屏触发越界错误
多分区UITableView接入SkeletonView数组越界问题修复
报错根因定位
- 骨架屏渲染阶段的空数组越界:在
viewDidAppear触发骨架屏展示时,模拟业务数据需要等待5秒才会填充到data数组中,此时数组为空;但现有数据源实现中,计算分区数、计算分区行数、配置Header内容的逻辑,都直接用传入的section索引访问空的data数组,直接触发下标越界。 - Cell数据索引匹配错误:
cellForRowAt方法的取值逻辑完全和多分区数据结构不匹配:- 本该通过
indexPath.section取当前分区的数据源字典,代码错写成self.data[indexPath.row] - 本该从当前分区的
record数组中通过indexPath.row取行数据,代码错把分区维度的字典强行解包取name字段赋值给cell,逻辑完全错位
- 本该通过
- 骨架屏接口重复调用:同时执行
showAnimatedGradientSkeleton()和showAnimatedSkeleton(usingColor:transition:)两个启动方法,会重复触发表格的骨架屏渲染流程,放大越界问题的触发概率 - Header复用逻辑错误:把Header视图当成普通表格单元格从cell队列中复用,没有使用专门的Header/Footer复用队列,也没有在骨架屏渲染阶段做空值保护
正确适配实现步骤
- 增加全链路数组访问保护:所有通过下标访问
data数组的位置,先判断索引是否在数组有效范围内,禁止直接强行下标取值。可封装统一的安全取数方法:// 安全获取指定分区的数据源,越界时返回nil func safeSectionData(at section: Int) -> [String: Any]? { guard section >= 0, section < data.count else { return nil } return data[section] } - 修正多分区场景下的Cell数据取值逻辑:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "TeacherCell") as! TeacherTableViewCell // 按层级取数,每一步加校验 guard let sectionData = safeSectionData(at: indexPath.section), let recordList = getArray(withDictionary: sectionData["record"]), indexPath.row < recordList.count else { // 骨架屏渲染阶段拿不到真实数据时,返回空占位cell即可 return UITableViewCell() } let rowData = recordList[indexPath.row] cell.teacherName.text = rowData["name"] as? String return cell } - 适配SkeletonView的多分区占位逻辑,重写两个核心可选协议方法,让骨架屏渲染阶段不依赖真实业务数据:
numSections(in skeletonView: UITableView):直接返回预期的固定占位分区数(比如要展示4个分区的骨架效果,就返回4),不要直接绑定data.count(初始阶段数组为空,绑定就会越界)skeletonView(_ skeletonView: UITableView, numItemsInSection section: Int):按分区返回预期的固定占位行数(比如每个分区展示2行骨架,就返回2),让骨架屏在独立的渲染循环里完成占位效果绘制,不需要访问真实业务数组
- 调整骨架屏的配置与启动逻辑:
- 把
tableView.isSkeletonable = true的配置挪到viewDidLoad中完成,不要延迟到viewDidAppear才配置 - 去掉重复的骨架屏启动方法,仅保留一个动画效果的启动接口即可
- 模拟数据加载完成后,按顺序执行:调用
stopSkeletonAnimation()→ 调用hideSkeleton()→ 调用tableView.reloadData(),完成真实数据的展示
- 把
- 修正Header的实现逻辑:
- 将自定义Header类的父类改为
UITableViewHeaderFooterView,在视图初始化阶段用register(_:forHeaderFooterViewReuseIdentifier:)完成Header视图的注册 - 配置Header内容时同样增加空值保护,骨架屏阶段拿不到真实分区数据时,返回空占位视图,不要强行解包取值
- 将自定义Header类的父类改为
SkeletonView依赖文档获取路径
- 通过CocoaPods安装完成后,在项目的Pods目录下找到SkeletonView源码文件夹,文件夹内自带完整的使用说明README、多场景适配的示例工程,不需要跳转外部站点查阅
- 所有公开API的用法都在源码的头文件注释中有详细标注,包括多分区表视图、集合视图、嵌套视图的骨架屏配置细节
内容的提问来源于stack exchange,提问作者user10469417
相关产品推荐
相关产品推荐

