前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS性能优化-iOS 页面优化

iOS性能优化-iOS 页面优化

原创
作者头像
conanma
修改2021-11-04 11:56:15
2.6K1
修改2021-11-04 11:56:15
举报
文章被收录于专栏:正则

优化布局计算

关于auto layout的布局,最直接的优化是使用手动布局计算frame

因为自动布局的原理是:通过创建一个与view绑定的对象engine,使用engine记录下来相关的约束信息,在布局计算的时候,带入相关参数计算出来frame.

如果能去掉这一步,肯定是能节省性能的。

虽然iOS 12系统之后,苹果对auto layout进行了优化,优化后的效率和手动布局差不太多。但是我们的用户还是会有很多在12系统以下的。

因此,还是可以考虑优化的。

不过我目前还没有遇到过使用auto layout造成页面性能出现问题的案例。

异步耗时操作

图片解码操作

图片为什么需要解码?

首先我们项目里的本地图和加载过来的网图,都是经过压缩的二进制数据(常用的jpgpng)。

在显示到界面上的时候,需要将这些二进制数据绘制到对应的“画布”上。

这个绘制的过程就是解码。

异步图片解码

系统会默认在UIImage加载到UIImageView或者CALayercontent上的时候,在主线程进行解码。

这个解码操作是耗时的,如果不处理可能会造成卡顿问题,因此需要放到子线程里去异步执行。

我们使用的三方框架都有此类处理。

比如SDWebImage是创建了一个串行队列,异步执行解码操作。

通过SDWebImageAvoidDecodeImage参数可以控制是否进行解码操作。

不过这里有个疑惑,为什么不使用并发队列?使用串行队列就意味着图片解码操作要顺序执行,这样效率岂不是有点低?

缓存高度

对于不同cell的滑动列表,可以利用缓存来避免多次计算,达到提效的目的。

可以做的简单点利用数据模型来持有这些信息。

也可以利用三方的框架: UITableView+FDTemplateLayoutCell

解决图片问题

图片占有内存问题

从上图可以看到,图片占用内存的大小计算方式是: width * height * 每个像素占用的内存大小(一般是4字节)

一张图,如果分辨率比较大,就容易造成很大的内存问题

当页面上有多个图片的时候,这个内存就会暴增。

避免无谓的解码操作

SDWebImage在加载图片的时候默认会进行解码操作。

网上随便找了三张图,使用SDWebImageManager去加载。在开启和关闭解码操作后,在开启解码操作的时候,内存占用了10M。 关闭解码操作的时候,内存占用了5M

使用第三方库的时候,如果只是预加载图片,可以考虑设置不解码。

DownSampling(向下采样)

DownSampling 就是在Decode的时候指定尺寸,只Decode部分数据,减少内存的使用。

比如我一个控件大小是100 * 100,但是原图可能是300 * 300的。使用DownSampling后,只需要解码少量数据就可以达到所需。

这个SDWebImage也已经支持,大家只需在加载图片的时候,利用context参数设置图片的大小和控件的大小相同即可。

代码语言:javascript
复制
@{SDWebImageContextImageThumbnailPixelSize:@(size)}

经过我的实验,效果还是很明显的。

网上找了6张大图。

在不进行DownSampling的情况下,加载6张图片都消耗了 25M

但是在使用DownSampling的时候,指定尺寸为100*100,内存直接降低到了 5M

目前运用到项目中的首页Feeds流上,效果很显著。在只加载不到三屏的情况下(一屏大概4-6张图),都节省了40M左右。

注意使用的时候传入的尺寸要考虑到高清屏的系数。

因此,我们在搭建界面的时候,尽量加载和控件一样大的图,否则可能你看到的只是一个小图,其实占用了很大的内存,同时还需要CPU帮你去做一些压缩,剪裁的工作。

如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群1012951431来获取一份详细的大厂面试资料为你的跳槽多添一份保障。

建议使用Image Assets去管理
  • 查找快 如果是放到bundle里,是需要遍历bundle的文件夹。但是Image Assets的查找做了优化。
  • 更加智能的缓存策略
  • 可以减少拆分后的包体积
  • 支持图片拉伸等特性。
减少Backing Store的使用
什么是backing store?

CALayercontents所指向的区域。

如果使用了draw函数,CALayer会创建一个与view相同尺寸的Backing store,在上面进行draw的操作,然后提交到frame buffer中用于渲染。

这一步会造成内存的消耗。

因为系统的UILabel对单色的string做了优化处理,可节省75%的Backing Store,并能自动更新Backing Storesize以适配富文本emoji

对于一些复杂的view样式,可以通过多个subView组合到一起来实现,尽量减少draw的操作,就可以减少这部分内存的消耗。

图片复用

对于纯色图片,尽量复用一个图片,用tint Color 来进行不同的渲染。达到复用图片的目的。

对于使用频繁的图片,可以使用[UIImage imageWithNamed:@""]方式创建,利用系统级别的缓存来提高效率,减少内存。

对于使用不频繁的图片,建议使用直接读文件的方式加载,用完就会自动释放,减少内存。

离屏渲染

什么是离屏渲染?

正常情况下,系统会按照60FPS或者120FPS的频率来执行渲染流程。

在每个屏幕渲染周期内,系统会从帧的缓冲区里拿到已经渲染好的数据,渲染到屏幕上。

而由于图层或者其他因素,导致在屏幕内无法直接渲染,需要在屏幕外开辟一个空间用来合成帧数据。

这就是所谓的离屏渲染。

离屏渲染的坏处

离屏渲染之所以不好,原因是:

1.开辟了一块额外的空间,内存增加了

2.切换环境造成的牺牲很大

很容易发生在渲染周期内,数据无法渲染好,因此造成卡顿问题。

造成离屏渲染的方式

关于离屏渲染,实际开发中基本上都是:

  • 圆角+剪裁的组合
  • 设置layer的mask
  • 设置阴影
  • 光栅化
  • 抗锯齿
解决离屏渲染

对于设置阴影造成的离屏渲染,解决方式就是使用贝塞尔曲线绘制好path,这样就能解决问题。

这里想更多的介绍一下圆角方面的优化。

对于UIImageView的圆角方案

最开始的时候,我的想法和网上的方案一样,就是:

利用子线程将图片进行切角处理,同时缓存下来这张图片,然后异步到主线程使用图片。这样就可以解决了圆角的离屏渲染问题。

但是在实际操作过程中,觉得这一步还是有问题的。

问题一:内存占用增加

在滑动列表里,我们不可能一直不停地对图片进行切圆角操作。

不然就需要一直消耗CPU进行切圆角操作,还要频繁切换线程。

因此,我们就需要使用空间换时间了,将切好的圆角图片也缓存下来。

这个时候问题来了:一张图,被网络框架加载并存储了一份,现在又存下来了一张圆角图片

那基本上意味着内存占用double了一下。

问题二:实现功能很容易,但是想写好太难

虽然网上给出了很多的demo,但是在我看来写的都不好。

  • 首先,很粗暴的放到了一个全局并发队列里进行绘制,没有考虑到线程的消耗和安全问题。
  • 其次是没有一个很完善的防重用逻辑。 一般我们都是使用的滑动视图,里面cell上的控件都是会重用的。如果不像SDWebImage一样先将之前的获取图片操作移除,如何确保重用的时候不出问题?
  • 使用起来麻烦 如果自己实现了一套获取图片的逻辑,会发现代码量增加很多,远远不如使用SDWebImage分类来的方便。(当然我们自己也可以使用一个分类来完成这个任务)

上面说的这些问题,其实都可以通过扩展SDWebImage来支持。

但是需要花费时间和精力来搞定,未来有机会的话,可以尝试一下。

我认为的圆角最优解

对现在有的机器(iphone 11)进行了简单的验证,使用异步绘制圆角图片的方案解决离屏渲染后,通过instrument的分析,发现CPUGPU都没有一个很明显的收益变化。

如果非得优化,让设计师切一个遮罩盖在上面是我认为的最好的解决方案。

毕竟前面也提到了,苹果认为组合subViews的方式比自己绘制的方式好很多。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 优化布局计算
  • 异步耗时操作
    • 图片解码操作
      • 图片为什么需要解码?
      • 异步图片解码
      • 缓存高度
    • 解决图片问题
      • 图片占有内存问题
      • 避免无谓的解码操作
      • DownSampling(向下采样)
      • 建议使用Image Assets去管理
      • 减少Backing Store的使用
      • 图片复用
    • 离屏渲染
      • 什么是离屏渲染?
      • 离屏渲染的坏处
      • 解决离屏渲染
      • 问题二:实现功能很容易,但是想写好太难
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档