iOS 胡说八道集JG专题

WWDC14_419_高级图形和动画

2015-05-05  本文已影响464人  seedante

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

视频内容

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。
根据视频内容探索了以下调试选项:

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

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 绘制圆角,这种机制导致了离屏绘制。
工程师的建议是:

总结:

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

上一篇下一篇

猜你喜欢

热点阅读