WWDC14_419_高级图形和动画

原标题为:《Advanced Graphics and Animation For iOS Apps》。下载的文件名有点不同。本笔记内容为视频学习和实践探索。另外 objc 的这篇文章《绘制像素到屏幕上》和本视频的内容有很大程度的交集,推荐一下。

视频内容

  • Core Animation pipeline
  • Rendering concepts
  • UIBlurEffect
  • UIVibrancyEffect
  • Profiling tools
  • Case studies
Core Animation Pipeline

这个章节的时长为06:35,但信息量非常大。每个小节拉出来都能另写一章。


屏幕内容的显示流程

让屏幕页面流畅应该保证页面刷新率为 60 帧/秒,1 帧的时间大概就是 16.67 ms了。Core Animation 这个框架的名字很具有误导性,让大家以为这个框架只是用来实现动画的,实际上 Core Animation 框架做了很多基础工作:组合屏幕上的内容,追踪视图结构和内容的变化。流程图中 Commit Transaction 前面的红框代表触发视图内容变化的事件,比如点击按钮,之后Core Animation 框架会捕获到屏幕内容的变化并提交给 Render Server(渲染服务器),Render Server 里另外一个版本的 Core Animation 框架负责解码并绘制内容。

动画处理的流程
Commit Transaction的具体过程

值得注意的是:在 Prepare 这个阶段做的事是图像解码以及图像转换。无论是网上下载的图像还是从磁盘读取图像文件,得到的图像一般是不能直接用于显示的,需要解码为位图(bitmap)。如果你的视图中使用了 JPEGs 或是 PNGs的图像,将在这个阶段进行解码;如果你使用了 GPU 不支持的图像格式(就是 JPEG 和 PNG 之外的格式),那么图像就需要转换格式。Path 团队的图像缓存开源库FastImageCache就利用这个特性来加速图像的显示。

Rendering concepts

这一节介绍了一些基本的渲染知识:屏幕被分割成 NxN 像素的小块来渲染,每个小块的大小与 SoC(System on Chip) 的cache相关。具体的操作过程如下:对于一个 app icon,被当做一个 CALayer 来渲染,而 CALayer 在 Core Animation 中被划分为两个三角形,每个三角形可以被继续分割成多个三角形,对每一个三角形单独渲染。

Layer in CoreAnimation is two triangles

split into multiple triangles

后面的,我看完之后基本就忘了,所以想了解到底怎么渲染的可以看看这一段。大致过程是渲染然后合成,在开头的文章中有对这块的叙述。

UIVisualEffectView

在 iOS 8 中苹果放出了新的 UIView 子类 UIVisualEffectView。苹果在 iOS 7 中广泛使用了虚化效果,却没有给出接口,民间大多使用 GPUImage 这个库来实现虚化效果,终于在 iOS 8 里给出了官方支持。UIVisualEffectView 支持 UIBlurEffect 和 UIVibrancyEffect 两种效果,前者是虚化内容,后者在前者的基础上再合成一个透明视图。

UIBlurEffect(虚化效果)的实现正是基于上一节提到的渲染+合成。其手法是这样:抓取用作背景的内容然后进行缩放以降低计算量,然后分别进行水平虚化和垂直虚化(翻译得可能不对,就是横着来一下,然后竖着来一下,而不是直接对整个内容进行虚化,降低计算量),最后将缩小的内容再放大到原来的尺寸进行着色。

虚化过程

效果有三种样式:Extra light, Light, Dark。这三种样式对性能的要求依次降低。另外 iPad 2以及 iPad 3不支持虚化(who care?)。而 UIVibrancyEffect 效果是在 UIBlurEffect 的基础上再合成一个视图。UIVibrancyEffect 效果对性能要求极高,苹果工程师建议避免对全屏使用该效果,并给出了优化性能的建议:Rasterization 和 Group Opacity。

1.Rasterization
设置 CALayer 的 shouldRasterize 属性为 YES 能够为程序触发离屏渲染(Offscreen Rendering),更新内容时能够额外渲染不在屏幕范围上的内容用作缓存;不要滥用,因为离屏渲染的缓存大小只有屏幕尺寸的 2.5 倍大;当离线渲染的内容超过 100 ms 没有使用将会被清除。应该在以下场景中才开启该属性:

  • 绘制代价很大的静态内容
  • 结构非常复杂的视图

要注意,离屏渲染的计算代价是很大的,与之相比,通过普通手段显示内容要廉价很多(有很多术语由于没有铺垫写出来只会更让人困惑,还是推荐看开头的文章)。只有当屏幕中的图层不变时才可以利用这个选项来优化。因此,在一般情况下,还是不要开启离屏渲染的好。
2.Group Opacity
如果一个 layer 的 opacity 值小于 1.0 并且该 layer 含有子 layer 或者有背景图像,开启groupopacity 将会触发离屏渲染。建议一直关闭该功能,将 layer 的 allowsGroupOpacity 设置为 NO。

Profiling Tool:

Xcode 套件中的 Instruments 工具估计是最没有被有效利用的工具之一,我以前就只用来查看内存占用以及泄露问题了。实际上利用 Instruments来对视图和动画性能调优是非常高效的。视图和动画的性能一旦有问题自然是非常不爽快的,相对于手工一遍遍主观调试,Instruments 能够直接指出性能不佳的部分,一目了然。
(Instruments 的文档令人发指,基本上找不到主讲工程师在视频中提到的 debug options)
主讲的工程师在介绍工具之前给出了性能调优的检查选项:


Performance Investigation Mindset
Core Animation Instrument

在 Xcode 的菜单栏中依次选择 Product->Profile 后,会启动 Instruments 工具,有多种分析和调试工具,选择 Core Animation。
根据视频内容探索了以下调试选项:

  • Color blended layers
    屏幕上绿色的部分表示该处的 layer 是 opaque (不透明的),这样 GPU 在合成时就不需要考虑该 layer 下面的内容直接输出该 layer 的内容就够了;红色的部分表示该处的内容需要 blend(混合),GPU 需要将该 layer 以及该 layer 下方的内容进行混合后才能输出,工作量大。


    IMG_0384.PNG
  • Color Hits Green and Misses Red
    该选项与前面提到的Rasterization有关。绿色表明离屏渲染的 cache 中还有该部分的缓存,红色表示该部分的缓存已被移除。
  • Color Copied Images
    前面提到过,图像要被解码后才能用于显示,GPU只支持对 JPEG 和 PNG 格式,其他格式的图像需要由 CPU 来转化解码,最好放在后台中解码。
    我在使用这个选项的时候未发现画面有任何变化,尝试了浏览 gif 也没有发现异样。看来需要使用这个选项的场景太少。
  • Color MisalignedImages
    找出对字节没有对齐的图像并进行着色。当图像尺寸与其容器 View 的尺寸不一样的时候,需要把该图像进行缩放。
  • Color Offscreen-Renderd Yellow
    将离屏渲染的部分标记为黄色,查找出触发离屏渲染的部分。
  • Color Compositing Fast-Path Blue
    将由显示硬件(原话为 display hardware)进行混合的 layers 标记为蓝色,这是个好事,因为这意味着 GPU 的工作更少。
  • Flash Updated Regions
    标记屏幕上正在刷新的内容为黄色。

看完这部分以后进行性能调优不用到处猜瓶颈所在了,直接使用工具查看。

OpenGL ES Driver Instruments

在 Xcode 6.3 里,这个组件是找不到的,应该是改名成 GPU Driver 了。这个组件可以用来统计大部分的运行参数:CPU 占用,视图帧率,渲染使用,设备使用以及更多参数。我开发中的 App 的帧率还没有超过 50 的,真是惨不忍睹。该组件可以回答性能优化列表「Performance Investigation Mindset」中前面三个问题。

以前很少使用 Instruments,也因为我目前做的东西很少需要使用这些工具,当然还有可能是因为不知道能做什么所以没法用,恶性循环。

View Debugging

Xcode 6 的新特性之一,可以在 Xcode 里实时查看 UI 结构了,但只支持通过 Xcode 运行的 app。相比大名鼎鼎的 Reveal 还是有不少差距的。
当然,两者的定位不一样。目前来说对于调试够用了。

选择调试工具
Case Study

案例学习这一块给出了两个常见的性能隐患:
1.阴影绘制
以前的常见代码:

CALayer *imageViewLayer = cell.imageView.layer;
imageViewLayer.shadowColor = [UIColor blackColor].CGColor;
imageViewLayer.shadowOpacity = 1.0;
imageViewLayer.shadowRadius = 2.0;
imageViewLayer.shadowOffset = CGSizeMake(1.0, 1.0)
//设置了上面这些属性后就能绘制阴影了,这样一来Core Animation 必须知道阴影的形状才能进行绘制,但这样就必须使用离屏渲染来渲染内容。(为啥,不明白)下面的方法可以避免离屏渲染。
imageViewLayer.shadowPath = CGPathCreateWithRect(imageRect, NULL)

2.圆角绘制
以往的常见代码:

CALayer *imageViewLayer = cell.imageView.layer; 
imageViewLayer.cornerRadius = imageHeight / 2.0;
imageViewLayer.masksToBounds = YES;

在给出的例子里,工程师使用一个 TableView 显示一些圆形头像。(由于说到关键时刻字幕消失了我听不懂了,所以不明白为什么这里产生了离屏渲染)我的理解是,由于重用机制,被重用的 Cell 每一次出现,Core Animation 都要为 Cell 绘制圆角,这种机制导致了离屏绘制。
工程师的建议是:

  • 不要对重用的 Cell 使用 mask。
  • 如果做不到上一点,尝试这个方法来:
    1.将 TableView 的背景设置为 solid white;
    2.在缩略图上方绘制一个圆形,圆形外围为白色;
    这样做减少了离屏渲染却也增加了混合两个图层的工作,但从性能上来说依然比原来好。

总结:

离屏渲染代价昂贵,尽量避免
1·利用工具 CA Instrument 来找出它们
2·知道怎么做来避免它们(上面的 shadowPath 就是一个例子)(这个比较上,还没搞清楚离屏渲染到底怎么触发的)
在不同的设备上测试性能
1·使用 OpenGL ES Driver Instrument 来观察 GPU
2·使用 Time Profiler Instrument 来观察 CPU
知道视图的结构和任何隐含的绘制成本
1·这个对于 table cells 和滚动比较重要

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

推荐阅读更多精彩内容