返回首页
SwiftUI 系列 08|SwiftUI List 的常见坑:刷新、删除、跳转与性能
SwiftUI2024年5月30日 04:305 分钟阅读
List 真正难的地方是数据身份、状态更新和交互行为一旦纠缠就很容易一起出问题
List 是 SwiftUI 里最容易“看起来很好写”,也最容易在真实业务里踩坑的控件之一。
因为很多简单例子都很顺:
- 数据一丢进去就能显示
- 下拉刷新也能接
- 删除、跳转、分区似乎都有现成能力
但一旦项目里开始出现:
- 分页
- 搜索
- 删除后状态联动
- 跳转详情再返回
- 图片加载
List 的问题就会逐渐暴露出来。
一、很多 List 问题的根源,是“数据身份”没想清楚
SwiftUI 的很多行为都和 identity 强相关。 如果列表数据“看起来一样”,但身份不稳定,后面就很容易出现:
- 刷新时跳动
- 删除时动画奇怪
- 返回列表后滚动位置异常
- 某一行内容刷新不对
所以 List 最基础也最容易被低估的一件事,是:
- 每个 item 的身份是不是稳定
- 这个身份在刷新、分页、搜索切换时是否仍然可信
很多列表“玄学 bug”,最后根因都在这里。
二、刷新和分页经常会把列表状态搞乱
因为刷新和分页本质上是在修改“当前列表集合”,而集合变化会直接影响:
- cell 复用关系
- 滚动位置
- 当前 loading 状态
- 空态与内容态切换
如果这些关系没理清,就很容易出现:
- 下拉刷新时列表闪一下
- 分页回来整个列表重算
- 旧结果覆盖新内容
所以 List 真正的难点经常是:
- 刷新时哪些状态该保留
- 分页时哪些状态该追加
- 同一类请求之间是否会并发冲突
三、删除操作经常不是“删掉一个元素”那么简单
表面上看,删除只是在数组里移掉一个元素。 但真实列表里,删除往往同时牵动这些东西:
- 当前展示集合
- 空态判断
- 选中态
- 跳转状态
- 后端同步状态
如果只是“先删再说”,很容易出现:
- 删除成功了,但详情页还指向旧对象
- 删除失败时列表和服务端状态不一致
- 动画没问题,但数据源回滚逻辑很混乱
这说明删除的真正难点是:
- 数据源到底谁拥有
- 删除是乐观更新还是等待服务端确认
- 删除后导航状态怎么收口
四、跳转容易和 List 纠缠出问题
常见的情况是把列表和跳转各自看成独立功能,但在真实项目里它们关系非常紧。
典型问题包括:
- 点进详情后删除当前项,返回列表状态不对
- 列表刷新后,原来的选中路径失效
- 搜索结果跳详情再返回,列表状态被重置
这些问题的本质通常是:
- 列表数据状态
- 选中项状态
- 导航路径状态
没有被当成同一组问题处理。
五、性能问题在 List 里特别容易爆
因为列表把很多小问题都会放大。
比如:
- item 视图层级太深
- 图片加载和解码太晚
- 文本和数据转换放在显示阶段做
- 刷新粒度过大
在普通页面里这些成本可能还能忍,但在 List 这种高频滚动场景里,很容易直接变成掉帧和闪动。
所以很多 List 性能问题,并是它对数据身份、刷新范围和展示时机特别敏感。
六、一个更稳的思路:先把 List 当“状态投影”,而不是“装数据的容器”
常见的情况是写列表时,脑子里默认是:
- 我有一组数据
- 放进 List
真实项目里更稳的思路是:
- 当前页面状态是什么
- 这组状态应该投影成哪一批列表项
- 哪些列表项有稳定身份
- 哪些用户动作会改变这组状态
一旦把 List 当成状态投影,而不是简单容器,很多问题就会开始变清楚:
- 要优先关注 identity
- 删除、刷新、分页不能分开看
- 跳转状态也要一起考虑
七、结论:List 的真正难点,是“身份、状态、交互”很容易一起缠住
换个更短的说法,我会说:
SwiftUI 里的
List真正难的地方,是数据身份、页面状态和删除/刷新/跳转这些交互一旦缠在一起,任何一个边界没立住,问题都会一起暴露。
所以想把 List 用稳,关键是先把:
- item 身份
- 列表状态
- 交互后状态流转
这三件事理顺。