一、Instrument
三个方法:
(1)、按下Command + I打开Instrument;
(2)、Xcode->product->profile;
(3)、Xcode->Open Developer Tool->Instrument
二、Core Animation工具
1、界面
2、简单介绍
注意这个调试必须使用真机,点击左上角的红色圆圈就会開始录制
我们须要了解两个两个区域:
1、这里记录了实时的fps数值。有些地方是0是由于屏幕没有滑动。
2、调试选项;
ps:有过游戏经验的人或许对fps这个概念比較熟悉。我们知道不论什么屏幕总是有一个刷新率,比方iphone推荐的刷新率是60Hz,也就是说GPU每秒钟刷新屏幕60次,因此两次刷新之间的间隔为16.67ms。
这段时间内屏幕内容保持不变。称为一帧(frame),fps表示frames per second,也就是每秒钟显示多少帧画面。对于精巧不变的内容,我们不须要考虑它的刷新率。但在运行动画或滑动时,fps的值直接反映出滑动的流畅程度。
三、调试、优化
1、Color Blended Layers
(1)、图层混合
首先我们要明确像素的概念,屏幕上每一个点都是一个像素,像素有R、G、B三种颜色构成(有时候还带有alpha值)。假设某一块区域上覆盖了多个layer,最后的显示效果受到这些layer的共同影响。举个样例。上层是蓝色(RGB=0,0,1),透明度为50%,下层是红色(RGB=1,0,0)。那么终于的显示效果是紫色(RGB=0.5,0,0.5)。
这样的颜色的混合(blending)须要消耗一定的GPU资源,由于实际上可能不止仅仅有两层。
假设仅仅想显示最上层的蓝色,能够把它的透明度设置为100%,这样GPU会忽略以下全部的layer,从而节约了非常多不必要的运算。
(2)、调试Color Blended Layers
第一个调试选项”Color Blended Layers”正是用于检測哪里发生了图层混合。并用红色标记出来。
因此我们须要尽可能降低看到的红色区域。
一旦发现应该想法设法消除它。開始调试后勾选这个选项,我们在手机上能够看到例如以下的场景:
重要的是backgroundColor属性。假设不设置这个属性。控件依旧被觉得是透明的。所以我们做的第一个优化是设置控件的backgroundColor属性。
PS:假设label文字有中文,依旧会出现图层混合,这是由于此时label多了一个sublayer。
2、Color Hits Green and Misses Red
(1)、光栅化
光栅化是将一个layer预先渲染成位图(bitmap),然后加入缓存中。假设对于阴影效果这样比較消耗资源的静态内容进行缓存,能够得到一定幅度的性能提升。demo中的这一行代码表示将label的layer光栅化:
label.layer.shouldRasterize = YES;
(2)、调试Color Hits Green and Misses Red
第二个调试选项是“Color Hits Green and Misses Red”,它表示假设命中缓存则显示为绿色,否则显示为红色,显然绿色越多越好,红色越少越好。
注意:光栅化的核心在于缓存的思想。我们自己动手把玩一下,能够发现以下几个有意思的现象:
上下微小幅度滑动时,一直是绿色
上下较大幅度滑动,新出现的label一開始是红色,随后变成绿色
假设精巧一秒钟。刚開始滑动时会变红。
这是由于layer进行光栅化后渲染成位图放在缓存中。
当屏幕出现滑动时,我们直接从缓存中读取而不必渲染,所以会看到绿色。当新的label出现时,缓存中没有个这个label的位图。所以会变成红色。第三点比較关键,缓存中的对象有效期仅仅有100ms,即假设在0.1s内没有被使用就会自己主动从缓存中清理出去。
这就是为什么停留一会儿再滑动就会看到红色。
光栅化的缓存机制是一把双刃剑。先写入缓存再读取有可能消耗较多的时间。因此光栅化仅适用于较复杂的、静态的效果。通过Instrument的调试发现。这里使用光栅化常常出现未命中缓存的情况,假设没有特殊须要则能够关闭光栅化,所以我们做的第二个优化是凝视掉以下这行代码
// label.layer.shouldRasterize = true
3、Color Copied Images
(1)、颜色格式
像素在内存中的布局和它在磁盘中的存储方式并不相同。考虑一种简单的情况:每一个像素有R、G、B和alpha四个值。每一个值占用1字节。因此每一个像素占用4字节的内存空间。
一张1920*1080的照片(iPhone6 Plus的分辨率)一共同拥有2,073,600个像素。因此占用了超过8Mb的内存。可是一张相同分辨率的PNG格式或JPEG格式的图片普通情况下不会有这么大。这是由于JPEG将像素数据进行了一种非常复杂且可逆的转化。
CPU主要处理两件事:
(1)把图片从PNG或JPEG等格式中解压出来,得到像素数据
(2)假设GPU不支持这样的颜色各式,CPU须要进行格式转换
比方应用中有一些从网络下载的图片。而GPU恰好不支持这个格式。这就须要CPU预先进行格式转化。
(2)、调试Color Copied Images
第三个选项“Color Copied Images”就用来检測这样的实时的格式转化,假设有则会将图片标记为蓝色。
4、Color Misaligned Images
(1)、图片大小
在项目中,我们网络请求图片。大小不一,可是展示的UIImageView有时候是固定大小。这时候我们就须要图片的缩放了。图片的缩放须要占用时间,因此我们要尽可能保证不管是本地图片还是从网络或取得图片的大小,都与其frame保持一致。
(2)、调试Color Misaligned Images
第五个选项“Color Misaligned Images”,它表示假设图片须要缩放则标记为黄色。假设没有像素对齐则标记为紫色。勾选上这个选项并进行调试。能够看到例如以下场景:
5、Color Offscreen-Rendered Yellow
(1)、离屏渲染
离屏渲染表示渲染发生在屏幕之外。离屏渲染意味着把渲染结果暂时保存,等用到时再取出,因此相对于普通渲染更占用资源。
(2)、调试Color Offscreen-Rendered Yellow
第六个选项“Color Offscreen-Rendered Yellow”会把须要离屏渲染的地方标记为黄色,大部分情况下我们须要尽可能避免黄色的出现。
离屏渲染可能会自己主动触发。也能够手动触发。以下情况可能会导致触发离屏渲染:
1、重写drawRect方法。(自己主动触发离屏渲染)
2、有mask或者是阴影(layer.masksToBounds, layer.shadow*)。模糊效果也是一种mask。(自己主动触发离屏渲染)
3、layer.shouldRasterize = true。(手动开启离屏渲染)
開始调试并勾选“Color Offscreen-Rendered Yellow”。会看到这样的场景:
能够看到tabbar和statusBar也是黄色,这是由于它们使用了模糊效果。
假设图片使用了阴影,也是黄色,这说明它也进行了离屏渲染,解决方式。在设置阴影效果的四行代码以下加入一行:
imgView.layer.shadowPath = UIBezierPath(rect: imgView.bounds).CGPath
这行代码制定了阴影路径。假设没有手动指定。Core Animation会去自己主动计算,这就会触发离屏渲染。假设人为指定了阴影路径。就能够免去计算,从而避免产生离屏渲染。
设置cornerRadius本身并不会导致离屏渲染,但非常多时候它还须要配合layer.masksToBounds = true使用。依据之前的总结,设置masksToBounds会导致离屏渲染。
解决方式是尽可能在滑动时避免设置圆角,假设必须设置圆角,能够使用光栅化技术将圆角缓存起来:
// 设置圆角
label.layer.masksToBounds = true
label.layer.cornerRadius = 8
label.layer.shouldRasterize = true
label.layer.rasterizationScale = layer.contentsScale
6、Color Compositing Fast-Path Blue
(1)、高速路径
离屏渲染的最后一步是把此前的多个路径组合起来。假设这个组合过程能由CPU完毕,就会大量降低GPU的工作。
这样的技术在绘制地图中可能用到。
(2)、调试Color Compositing Fast-Path Blue
第七个选项“Color Compositing Fast-Path Blue”用于标记由硬件绘制的路径,蓝色越多越好。
7、Flash updated Regions
(1)、变化区域
刷新视图时,我们应该把须要重绘的区域尽可能缩小。
对于未发生变化的内容则不应该重绘。
(2)、调试Flash updated Regions
第八个选项“Flash updated Regions”用于标记发生重绘的区域。
四、总结
1、避免图层混合
- ①、确保控件的opaque属性设置为true。确保backgroundColor和父视图颜色一致且不透明;
- ②、如无特殊须要。不要设置低于1的alpha值;
- ③、确保UIImage没有alpha通道;
2、避免暂时转换
- ①、确保图片大小和frame一致,不要在滑动时缩放图片。
- ②、确保图片颜色格式被GPU支持,避免劳烦CPU转换;
3、慎用离屏渲染
- ①、绝大多数时候离屏渲染会影响性能;
- ②、重写drawRect方法。设置圆角、阴影、模糊效果,光栅化都会导致离屏渲染;
- ③、设置阴影效果是加上阴影路径。
- ④、滑动时若须要圆角效果,开启光栅化。