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 和滚动比较重要

上一篇 下一篇

猜你喜欢

热点阅读