iOS性能调优实战之Instrument-Core Animation

由于app新版本增加好多动画,本身就是一个拍照为主的建模工具。所以对性能要求很高,所以性能调优尤为重要。Instrument有很多工具可以测试内存泄漏,测试动画帧率,所以用好它,能解决项目中卡顿问题,让app更健壮。(随便扯点先)

  • 先看下基本界面,点击Product->Profile 或者直接快捷键Command + i 打开Instrument
BEBFE50F-80E7-4FE2-9A19-A41492C029C2.png

Core Animation

它的作用就是查看fps的值,稍后会说这个fps是什么意思。第二个作用就是查看图层的渲染,图层的渲染是影响fps的关键。如果你的tableview滑动有卡顿,首先你会看到fps比较小。然后就查找原因,原因就在图层渲染上。如果渲染问题解决了,那fps就接近最高了,最高的是60。

FPS 屏幕每秒刷新的频率

任何屏幕总有一个刷新率,比如iphone推荐的刷新率是60Hz,也就是说GPU每秒钟刷新屏幕60次,因此两次刷新之间的间隔为16.67ms。这段时间内屏幕内容保持不变,称为一帧(frame),fps表示frames per second,也就是每秒钟显示多少帧画面。对于静止不变的内容,我们不需要考虑它的刷新率,但在执行动画或滑动时,fps的值直接反映出滑动的流畅程度。

注意用真机测试哦,点击上图的Core Animation,然后进入下图的界面,然后点左上角的⭕️按钮,就可以开始测试了。这就是我滑动tabelview的时候屏幕刷新的频次。0的时候就是我没有滑动。滑动的时候大约都是在50多(60最佳),说明滑动的还算顺。根据WWDC的说法,当FPS 低于45的时候,用户就会察觉到到滑动有卡顿。那就该分析下卡顿的原因。


7492DEB4-2898-4589-8C51-D0D6B246A32D.png
调试、优化,查看图层的渲染情况(关键问题)
屏幕快照 2017-07-08 下午12.18.15.png

我们可以用上图底部的Debug Options框子里的工具去调试。寻找掉帧的原因。接下来就一个个去用用它们。

Color Blended Layers 图层混合

三原色大家都知道吧,rgb,如果某一块区域上覆盖了多个view,最后的显示效果受到这些view的共同影响。举个例子,上层是蓝色(RGB=0,0,1),透明度为50%,下层是红色(RGB=1,0,0)。那么最终的显示效果是紫色(RGB=0.5,0,0.5)。这种颜色的混合(blending)需要消耗一定的GPU资源,因为实际上可能不止只有两层。如果只想显示最上层的蓝色,可以把它的透明度设置为100%,这样GPU会忽略下面所有的layer,从而节约了很多不必要的运算。

当勾选了Color Blended Layers之后会看到手机出现这样的场景,红色代表出先了图层混合,绿色的没事,所以我们就努力的去消除红色就行了。

IMG_6346.PNG

首先创建一个View,应该给他个颜色,不给就是默认透明,透明就有可能发生图层混合,所以这个是一个点。

UIImageView可以先给背景一个颜色,不仅它自身需要是不透明的,它的图片也不能含有alpha通道,如果有alpha通道就会发生图层混合。

label(哈哈哈)成红色,是因为一没有给文字的label增加不透明的背景颜色,而是当UILabel内容为中文时,label的实际渲染区域要大于label的size,因为外围有了一圈的阴影,才会出现图层混合所以就把超出的部分切一下,代码如下:

   UILabel *textLabel = [[UILabel alloc]initWithFrame:CGRectMake(100, 20, 80, 20)];
    textLabel.backgroundColor = [UIColor whiteColor];
    textLabel.layer.masksToBounds = YES;
    textLabel.text = [NSString stringWithFormat:@"哈哈哈"];
    [self.contentView addSubview:textLabel];

最后发现哈哈哈变绿了。

Color Hits Green and Misses Red 光栅化缓存图层命中

光栅化是将一个layer预先渲染成位图(bitmap),然后加入缓存中。如果对于阴影效果这样比较消耗资源的静态内容进行缓存,可以得到一定幅度的性能提升。

label.layer.shouldRasterize = true
label.layer.rasterizationScale = layer.contentsScale 

它表示如果命中缓存则显示为绿色,否则显示为红色,显然绿色越多越好,红色越少越好。

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

光栅化的缓存机制是一把双刃剑,先写入缓存再读取有可能消耗较多的时间。因此光栅化仅适用于较复杂的、静态的效果。通过Instrument的调试发现,如果使用光栅化经常出现未命中缓存的情况,如果没有特殊需要则可以关闭光栅化,而且光栅化会导致离屏渲染。

Color Copied Image (拷贝的图片)

这个选项主要检查我们有无使用不正确图片格式,由于手机显示都是基于像素的,所以当手机要显示一张图片的时候,系统会帮我们对图片进行转化。比如一个像素占用一个字节,故而RGBA则占用了4个字节,则1920 x 1080的图片占用了7.9M左右,但是平时jpg或者png的图片并没有那么大,因为它们对图片做了压缩,但是是可逆的。所以此时,如果图片的格式不正确,则系统将图片转化为像素的时间就有可能变长。而该选项就是检测图片的格式是否是系统所支持的,若是GPU不支持的色彩格式的图片则会标记为青色,则只能由CPU来进行处理。CPU被强制生成了一些图片,然后发送到渲染服务器,而不是简单的指向原始图片的的指针。我们不希望在滚动视图的时候,CPU实时来进行处理,因为有可能会阻塞主线程。一般不会出现这种情况。如果有则会将图片标记为蓝色。

Color Misaligned Image (图片大小)

这里会高亮那些被缩放或者拉伸以及没有正确对齐到像素边界的图片,即图片Size和imageView中的Size不匹配,会使图过程片缩放,而缩放会占用CPU,所以在写代码的时候保证图片的大小匹配好imageView,如果图片需要缩放则标记为黄色,如果没有像素对齐则标记为紫色。

Color Offscreen- Rendered Yellow (离屏渲染)

离屏渲染就是GPU渲染发生在屏幕外。

先看看正常的渲染首先OpenGL提交一个命令到Command Buffer,随后GPU开始渲染,渲染结果放到Render Buffer中,这是正常的渲染流程。

但是有一些复杂的效果无法直接渲染出结果,它需要分步渲染最后再组合起来,比如为相机图标添加一个蒙版(mask):在前两个渲染通道中,GPU分别得到了纹理(texture,也就是那个相机图标)和layer(蓝色的蒙版)的渲染结果。但这两个渲染结果没有直接放入Render Buffer中,也就表示这是离屏渲染。直到第三个渲染通道,才把两者组合起来放入Render Buffer中。离屏渲染意味着把渲染结果临时保存,等用到时再取出,因此相对于普通渲染更占用资源。

Color Offscreen-Rendered Yellow”会把需要离屏渲染的地方标记为黄色,大部分情况下我们需要尽可能避免黄色的出现。离屏渲染可能会自动触发,也可以手动触发。以下情况可能会导致触发离屏渲染:

  • 为图层设置遮罩(layer.mask)
  • 将图层的layer.masksToBounds / view.clipsToBounds属性设置为true
  • 将图层layer.allowsGroupOpacity属性设置为YES和layer.opacity小于1.0
  • 为图层设置阴影(layer.shadow *)。
  • 为图层设置layer.shouldRasterize=true
  • 具有layer.cornerRadius,layer.edgeAntialiasingMask,layer.allowsEdgeAntialiasing的图层
  • 文本(任何种类,包括UILabel,CATextLayer,Core Text等)。
  • 使用CGContext在drawRect :方法中绘制大部分情况下会导致离屏渲染,甚至仅仅是一个空的实现。

如果设置阴影,可以给阴影一个路径,

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

总结

避免图层混合

确保控件的opaque属性设置为true,确保backgroundColor和父视图颜色一致且不透明
如无特殊需要,不要设置低于1的alpha值
确保UIImage没有alpha通道

避免临时转换

确保图片大小和frame一致,不要在滑动时缩放图片
确保图片颜色格式被GPU支持,避免劳烦CPU转换

慎用离屏渲染

绝大多数时候离屏渲染会影响性能
重写drawRect方法,设置圆角、阴影、模糊效果,光栅化都会导致离屏渲染
设置阴影效果是加上阴影路径
滑动时若需要圆角效果,开启光栅化

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容