性能优化

翻译过来,大概的意思就是图层颜色混合。

我们知道GPU是图形硬件,主要的工作是混合纹理并算出像素的RGB值,这是一个非常复杂的计算过程,计算的过程越复杂,所需要消耗的时间就越长,GPU的使用率就越高,这并不是一个好的现像,而我们需要做的是减少GPU的计算量。

基本概念
我们要明白像素的概念。屏幕上每一个点都是一个像素点,颜色由R、G、B、alpha组成。如果某一块区域上覆盖了多层layer,最后所计算出来的显示的颜色效果,会受到这些layer的共同影响。

举个例子:

上层是蓝色(RGB=0,0,1),透明度为50%,下层是红色(RGB=1,0,0)。那么最终的显示效果是紫色(RGB=0.5,0,0.5)。

这种颜色的混合(blended)需要消耗一定的GPU资源,在实际开发中可能不止只有两层。如果只想显示最上层的颜色,可以把它的透明度设置为100%,这样GPU会忽略下面所有的layer,从而节约了很多不必要的运算。

在优化之前,我们通过模拟器->Debug->Color Blended Layers可看到上图的效果。我们发现有好多混合的地方,这都是影响滚动时流畅性的。

优化后,绿色越多越好,有混合颜色就要想办法去解决。
可以的话,要求美工在切图的时候,一定不要切出那些留有透明区域的图片,不然在你显示图片的时候,同样会出现像素混合问题。

UILable的优化:
在iOS8以前的版本:UILabel使用的是CALayer作为底图层
在iOS8及其以上版本:UILabel的底图层变成了_UILabelLayer,绘制文本也有所改变
结局方案:
1、设置UILable的背景色和父视图的背景色相同,且不透明。(中文文本除外);
2、设置lable.layer.maskToBounds = YES;(不过在iOS8之前,我们不用设置它的)

额外的知识点:
Color Copied Images:
简而言之,苹果的GPU只解析32bit的颜色格式,记住是32bit。
如果你放一张图片,而它的颜色格式却不是32bit,CPU会先进行颜色格式转换,再让GPU渲染。乖乖的CPU就默默做了这个多余的工作。
所以给你两个选择:
* 让设计湿都给你切32bit的图
* 自己去跑个异步线程来转换颜色去吧,不要去堵塞本来就压力很大的主线程!(就算异步转换颜色,也会导致性能损耗,比如电量增多,发热强变大等等等等。)

Color Misaligned Images
Misaligned Image表示要绘制的点无法直接映射到频幕上的像素点,此时系统需要对相邻的像素点做anti-aliasing反锯齿计算,增加了图形负担,通常这种问题出在对某些View的Frame重新计算和设置时产生的。
很简单,不要出现image size与imageView size不同的情况,这样会触发反锯齿计算,增加性能损耗。
实际开发中,本地的图片比较好把控,只需要写好对应的尺寸就好了,但是对于download下来的图片,可以在加载完后进行size处理,以满足imageView frame。特别是对于很多app,有大量的tableview,如果进行处理,则会大幅度提高流畅度。

Color Offscreen-Rendered
离屏渲染
这个东西讲起来感觉非常复杂,我觉得只需要知道,离屏渲染会导致CPU在后台保存一份bitmap,所以会导致CPU多余运算。
而避免的方式则是避免去做触发的动作:
1.重写drawRect方法
2.有mask或者是阴影(layer.masksToBounds, layer.shadow*),模糊效果也是一种mask
3.其他一些手动触发离屏渲染的动作,如layer.shouldRasterize = true

当图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制时,屏幕外渲染就被唤起了。屏幕外渲染并不意味着软件绘制,但是它意味着图层必须在被显示之前在一个屏幕外上下文中被渲染(不论CPU还是GPU)。图层的以下属性将会触发屏幕外绘制:
圆角(当和maskToBounds一起使用时)
图层蒙板
阴影
屏幕外渲染和我们启用光栅化时相似,除了它并没有像光栅化图层那么消耗大,子图层并没有被影响到,而且结果也没有被缓存,所以不会有长期的内存占用。但是,如果太多图层在屏幕外渲染依然会影响到性能。
有时候我们可以把那些需要屏幕外绘制的图层开启光栅化以作为一个优化方式,前提是这些图层并不会被频繁地重绘。
对于那些需要动画而且要在屏幕外渲染的图层来说,你可以用CAShapeLayer,contentsCenter或者shadowPath来获得同样的表现而且较少地影响到性能。

光栅化
光栅化是将一个layer预先渲染成位图(bitmap),然后加入缓存中。如果对于阴影效果这样比较消耗资源的静态内容(如果内容变化,光栅化后会产生大量的离屏渲染)进行缓存,可以得到一定幅度的性能提升。demo中的这一行代码表示将label的layer光栅化:
label.layer.shouldRasterize = true

光栅化的核心在于缓存的思想。我们自己动手把玩一下,可以发现以下几个有意思的现象:
1.上下微小幅度滑动时,一直是绿色
2.上下较大幅度滑动,新出现的label一开始是红色,随后变成绿色
3.如果静止一秒钟,刚开始滑动时会变红。
这是因为layer进行光栅化后渲染成位图放在缓存中。当屏幕出现滑动时,我们直接从缓存中读取而不必渲染,所以会看到绿色。当新的label出现时,缓存中没有个这个label的位图,所以会变成红色。第三点比较关键,缓存中的对象有效期只有100ms,即如果在0.1s内没有被使用就会自动从缓存中清理出去。这就是为什么停留一会儿再滑动就会看到红色。

光栅化的缓存机制是一把双刃剑,先写入缓存再读取有可能消耗较多的时间。因此光栅化仅适用于较复杂的、静态的效果。光栅化会导致离屏渲染

总结
如果你一步一步做到了这里,我想一定会有不少收益。不过,学而不思则罔,思而不学则殆。动手实践后还是应该总结提炼,优化滑动性能主要涉及三个方面:
1.避免图层混合
* 确保控件的opaque属性设置为true,确保backgroundColor和父视图颜色一致且不透明
* 如无特殊需要,不要设置低于1的alpha值
* 确保UIImage没有alpha通道
2.避免临时转换
* 确保图片大小和frame一致,不要在滑动时缩放图片
* 确保图片颜色格式被GPU支持,避免劳烦CPU转换
3.慎用离屏渲染
* 绝大多数时候离屏渲染会影响性能
* 重写drawRect方法,设置圆角、阴影、模糊效果,光栅化都会导致离屏渲染
* 设置阴影效果是加上阴影路径
* 滑动时若需要圆角效果,开启光栅化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值