iOS 保持界面流畅的技巧

iOS 保持界面流畅的技巧这篇文章十分详细的介绍了保持iOS界面流畅的一些技巧, 它从原理入手, 由浅入深认真读完受益匪浅. 他由YYKit框架的开发者亲笔所写.YYKit也是我们经常用来提高开发效率的工具之一.

影响流畅度的主要原因:

1、文本宽高计算、视图布局计算

2、文本渲染、图片解码、图形绘制

3、对象创建、对象调整、对象销毁

布局

Masonry

一口气update所有约束

一个约束会先在已添加的约束数组中找到该约束,然后更新该约束,如果找不到就install添加相应的约束。从这个update的功能来看其效率是比较低的。

remake

就是重新制作,如果之前已经添加过约束的话就先移除掉,然后再添加新的约束。在Masonry中remake效率是最低的

make + update (使用make来初始化控件的布局,使用update来更新所需要更新的约束)

因为设置值的时候我们依然采用的Update来更新的约束,只不过不是更新所有的约束,而是更新那些只需要更新的约束。因为更新的约束的量会少一些,所有FPS的表现效果会比之前更新所有的约束会更好一些。make + update的方式会是FPS稍微改善一些,但改善的并不是特别好。

frame + frame(不适用autolayou,直接使用frame布局,然后使用frame更新布局)

不用Masonry来布局了,我们直接使用Frame布局。因为Autolayout最终仍然会转换为Frame布局的,很显然Frame布局在性能方面是优于Autolayout布局的。来我们就来使用Frame布局然后使用Frame更新,FPS还算说得过去

结论

Remake的性能是最差的,所以我们在使用Masonry时尽量要少使用Remake。对控件的更新只一味的选择使用Update也不是一个好的选择,如果要使用Masonry框架还要对控件进行布局更新的话,最好是把那些不变的约束和需要更新的约束分开。使用make来添加相关约束,使用update来修改需要更新的约束。当然使用Frame布局的性能会好一些,不过布局过程过于繁琐不便于进行屏幕的适配。

文本

Label设置NSAttributedString的操作是比较耗时的操作。还有一个要明确一点的是,属性字符串的创建和生成并不会占用多少时间,而属性字符串的赋值和渲染所占用的时间是比较多的,

TableView

在哪里进行数据绑定

在UITableView的dataSource中实现的tableView:cellForRowAtIndexPath:方法,需要为每个cell调用一次,它应该快速执行。所以你需要尽可能快地返回重用cell实例。不要在这里去执行数据绑定,因为目前在屏幕上还没有cell。为了执行数据绑定,可以在UITableView的delegate方法tableView:willDisplayCell:forRowAtIndexPath:中进行。这个方法在显示cell之前会被调用。

快速计算动态cell的高度

UITableView是通过计算所以cell的高度之和来计算contentSize的值。UITableView的delegate方法tableView:heightForRowAtIndexPath:会为每个cell调用一次,所以你应该非常快地返回高度值。尽量不适用UITableViewAutomaticDimension的方式来自动计算行高

推荐使用框架

FDTemplateLayoutCell

渲染

opaque

把UIView的opaque设置为true。文档中说它用于辅助绘图系统定义UIView是否透明。如果不透明,则绘图系统在渲染视图时可以做一些优化,以提高性能。

混合(blending)

渲染最慢的操作之一是混合(blending)。混合操作由GPU来执行,因为这个硬件就是用来做混合操作的(当然不只是混合)。在iOS模拟器上运行App,在模拟器的菜单中选择’Debug‘,然后选中’Color Blended Layers‘。然后iOS模拟器就会将全部区域显示为两种颜色:绿色和红色。绿色区域没有混合,但红色区域表示有混合操作。

CPU和GPU渲染

CoreGraphics是使用CPU渲染, CoreAnimation是使用GPU渲染(开启CALayer.shouldRasterize ,可转嫁到CPU上).让CPU来执行某些渲染任务,从而减少GPU负载,因为在很多情况下,CPU可能不是100%负载的。优化混合操作的关键点是在平衡CPU和GPU的负载。所以我们要优化代码,以平衡CPU和GPU的负载。你需要清楚地知道哪部分渲染需要使用GPU,哪部分可以使用CPU,以此保持平衡。

实际操作:

多个透明元素重叠显示的性能问题。

解决方案:合并成一张图显示 原理:CPU方面,减少了UIKit的创建消耗,GPU方面,避免了合成渲染产生的消耗。 AsyncDisplayKit(现在叫Texture),针对多个透明元素的重叠,预合并无点击响应,不改变动画的图层。 Texture的保持流畅的原理:UIKit不是线程安全的,所以必须在主线程改动。Texture利用中间变量存储改动,保证线程安全,在合适的机会将并发操作同步到主线程。

静态cell、多图待加载的优化

解决方案:合并成一张图显示; 原理:提升I/O速度,一个大文件的读取速度,通常比多个小文件要快。

展示适合界面尺寸图片,不进行拉伸缩放。

解决方案:从服务器拉取合适尺寸的图片(例如七牛的服务就带裁剪/压缩参数); 原理:过大图片对内存消耗巨大(图片占用内存 = 图像高×图像宽×像素位数);不符合UIImageView尺寸的图片,进行重新缩减/放大尺寸的消耗是非常巨大的。

imageNamed和imageWithContentsOfFile

这个知道的人比较多,因为缓存图片的消耗通常是肉眼可见的多。常用的元素例如icon之类的,采用imageNamed:,系统会有缓存。如果是较大或者不常用的图片资源,采用imageWithContentsOfFile:。

避免出现不必要的子像素抗锯齿操作

什么情况下会触发子像素抗锯齿:

  1. 最常发生的情况是通过代码计算而变成浮点值的视图坐标

  2. 一些不正确的图片资源,这些图片的大小不是对齐到屏幕的物理像素上的(例如,你有一张在Retina显示屏上的大小为60x61的图片,而不是60x60的)。

如何找到问题所在: 在iOS模拟器上运行程序,在”Debug“菜单中选中”Color Misaligned Image“。品红色区域会执行子像素渲染,而黄色区域是图片大小

解决办法:

  1. 没有对齐的情况。对所有像素相关的数据做四舍五入处理,包括点坐标,UIView的高度和宽度。

  2. 跟踪你的图像资源:图片必须是像素完美的,否则在Retina屏幕上渲染时,它会做不必要的抗锯齿处理。

  3. 定期复查你的代码,因为这种情况可以会经常出现。

异步绘制UI

使用YYKit和Texture框架