iOS复杂列表滑动优化零碎整理(一)

大家好,今天就讲讲iOS UI的一些优化知识点,平常也会遇到,就分享出来。

何时做优化

不提倡过渡、提前优化,在技术选型,框架做好之后先做设计还原,之后再看性能瓶颈,多看 Instruments,少猜测,如很多教程所言Instruments 可以看到卡顿时 GPU 和 CPU 的负载,现在还多了 Display 工具。可以看到每次垂直同步期间内的详细绘制情况。

如何做优化

在 16.67ms (理论时间,其实更短) 内如果 CPU 或 GPU 没有完成内容提交,都会造成卡顿。现在的设备芯片性能越来越好,目前主要瓶颈都在 CPU,这里我们来讲一下目前针对 CPU 性能瓶颈做了哪些优化。

初级

数据预处理,预加载

比如首页长列表上面是滚动楼层,下面是推荐楼层,一般是 2 个 api,可以让服务层或者移动网关进行 api 合并,统一返回(盒马生鲜),或者自己选择合适的时机提前去加载,避免滑到推荐楼层再去加载数据。

预加载是对于无限瀑布流情况下 滑动到 5 的时候去加载下一页 10-20 的数据。

耗时操作丢到子线程

没什么好讲的,避免读写,计算

图片异步解码

说初级是因为现在大部分框架都帮我们做掉了

中级

图片格式优化

  • 静态图
    jpg 体积小,可以节省流量提升显示速度,加载可选渐进显示。png 体积较大,但是它带 alpha 通道,iOS系统针对解码有优化。
    看上去很简单,网络图片用 jpg,本地放的 png(在线压缩一下)。
    为什么说是中级呢,这里有个场景就是首页有大量图片广告都是带圆角的,jpg 切圆会有白底,用 png 尺寸太大了,你懂的,电商首页除了图就是图。怎么解决,后来参考了下每日优鲜,商品卡片白色底而且四周有 padding,有白边,看不到就行了。

  • 动态图
    电商首页除了图还有别的,就是会动的图。都说 webP 比 gif 好太多了,Benchmark 我就不发了,随便一搜很多。阿里云在线示例也提供了对比。
    问题是 webP 虽好,你去找设计要,设计会告诉你做不了,导不了这个格式。要用 AI 装插件,导出 Apng 再用 Google 爸爸的工具转。和设计折腾了半天,转出来是转出来了,效果和成本都不尽如人意。
    还有一条路,就是用阿里云的在线格式转换,马上跑去试了一下耗时感人。
    我想我知道都 2020 年了,大家还没用上 webP 的原因了。

系统 API 优化

真做过优化的肯定都知道,系统有几个 API 是挺耗时的

还有就是 swift 的高阶函数,编译器有优化,我们数据处理用了很多 map,参考 https://www.skoumal.com/en/performance-of-built-in-higher-order-functions-map-filter-reduce-and-flatmap-vs-for-in-loop-in-swift/

布局优化

说的就是 AutoLayout 的性能问题,虽然号称 iOS 12得到了优化,但是在瀑布流商品快速滑动测试中表现的还是不尽如人意。但是我们也不可能用回 frame 布局,太恶心。


解决方法 https://github.com/layoutBox/FlexLayout ,就是 Facebook 的 Yoga 套了个盒子布局的 api。

具体的性能对比这里有 https://github.com/layoutBox/LayoutFrameworkBenchmark 。

目前性能要求高的页面已经全部在切过去了。

高度缓存

cell 高度缓存,瀑布流高度缓存,能计算一次就只计算一次。

API 拿到 business model 转换成 view model 的时候就做好了丢到视图,由数据驱动,数据不变高度不变。

复用策略

这里其实比较重要的,因为有的复杂一点的楼层在 bind model 的时候才知道内部层级和布局,所以每次都要重绘,严重影响性能。其实一个 cell 复用的情况无非就是这几种

  1. 重新创建
  2. 有实例,需要绑数据
  3. 数据相同,直接用

安卓的 Recyclerview 有四级缓存,比较友好,你只要实现 onCreateViewHolder 和onBindViewHolder 就行。他自己有个类似数据的 diff 会判断复用的 视图需不需要重新绑定。

iOS 没有,怎么办呢,数据驱动

  1. 数据源里楼层类型唯一,标记为不复用,dequeueReusableCell 拿到的 cell 只要判断绑定的model 是不是 nil,nil 的话就是复用池满了被销毁了重新创建的,那需要重新绑数据。否则就直接用。
  2. 数据源里不唯一,但是绑定开销又特别大的 identifier 定制一下,数据类型加时间戳之类的唯一标识符,尽量让他不复用。

局部刷新

IGListKit 的强奸包,其实电商首页很少有局部刷新的场景,用起来也不像它的 Demo 那样简单,真要用好还是要仔细看看它的 diff 算法。

高级

经过上面一些操作,在测试机 se 上能稳定在 55 帧以上了。

按需加载图片

就是滑动停止的时候加载可见区域的网络图片,这个不难,只不过我们的 placeholder 太丑了,没有做骨架屏,就没有做。

Texture 、AsyncDisplayKit

去年做过 Texture + IGlistkit 框架的页面,上手成本比较高,Texture 有各种闪烁问题。最关键的是全埋点抓不到,所以基本不再考虑了。

青山不改,绿水长流。谢谢大家!

posted @   一眼万年的星空  阅读(280)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示