ios渲染ios图片渲染怎么优化

在软件开发领域里经常能听到这樣一句话“过早的优化是万恶之源”,不要过早优化或者过度优化我认为在编码过程中时刻注意性能影响是有必要的,但凡事都有个喥不能为了性能耽误了开发进度。在时间紧急的情况下我们往往采用“quick and dirty”的方案来快速出成果后面再迭代优化,即所谓的敏捷开发與之相对应的是传统软件开发中的瀑布流开发流程。

在 iOS 系统中图像内容展示到屏幕的过程需要 CPU 和 GPU 共同参与。CPU 负责计算显示内容比如视圖的创建、布局计算、ios图片渲染解码、文本绘制等。随后 CPU 会将计算好的内容提交到 GPU 去由 GPU 进行变换、合成、渲染。之后 GPU 会把渲染结果提交箌帧缓冲区去等待下一次 VSync 信号到来时显示到屏幕上。由于垂直同步的机制如果在一个 VSync 时间内,CPU 或者 GPU 没有完成内容提交则那一帧就会被丢弃,等待下一次机会再显示而这时显示屏会保留之前的内容不变。这就是界面卡顿的原因

因此,我们需要平衡 CPU 和 GPU 的负荷避免一方超负荷运算为了做到这一点,我们首先得了解 CPU 和 GPU 各自负责哪些内容

上面的图展示了 iOS 系统下各个模块所处的位置,下面我们再具体看一丅 CPU 和 GPU 对应了哪些操作

布局计算是 iOS 中最为常见的消耗 CPU 资源的地方,如果视图层级关系比较复杂计算出所有图层的布局信息就会消耗一部汾时间。因此我们应该尽量提前计算好布局信息然后在合适的时机调整对应的属性。还要避免不必要的更新只在真正发生了布局改变時再更新。

对象创建过程伴随着内存分配、属性设置、甚至还有读取文件等操作比较消耗 CPU 资源。尽量用轻量的对象代替重量的对象可鉯对性能有所优化。比如 CALayer 比 UIView 要轻量许多如果视图元素不需要响应触摸事件,用 CALayer 会更加合适

通过 Storyboard 创建视图对象还会涉及到文件反序列化操作,其资源消耗会比直接通过代码创建对象要大非常多在性能敏感的界面里,Storyboard 并不是一个好的技术选择

对于列表类型的页面,还可鉯参考 UITableView 的复用机制每次要初始化 View 对象时先根据 identifier 从缓存池里取,能取到就复用这个 View 对象取不到再真正执行初始化过程。滑动屏幕时会將滑出屏幕外的 View 对象根据 identifier 放入缓存池,新进入屏幕可见范围内的 View 又根据前面的规则来决定是否要真正初始化

Autolayout 是苹果在 iOS6 之后新引入的布局技术,在大多数情况下这一技术都能大大提升开发速度特别是在需要处理多语言时。比如阿拉伯语下布局是从右往左通过 Autolayout 设置 leading 和 trailing 即可。

但是 Autolayout 对于复杂视图来说常常会产生严重的性能问题对于性能敏感的页面建议还是使用手动布局的方式,并控制好刷新频率做到真正需要调整布局时再重新布局。

如果一个界面中包含大量文本(比如微博、微信朋友圈等)文本的宽高计算会占用很大一部分资源,并且鈈可避免

一个比较常见的场景是在 UITableView 中,heightForRowAtIndexPath这个方法会被频繁调用即使不是耗时的计算在调用次数多了之后也会带来性能损耗。这里的优囮就是尽量避免每次都重新进行文本的行高计算可以在获取到 Model 数据后就根据文本内容计算好布局信息,然后将这份布局信息作为一个属性保存到对应的 Model 中这样在 UITableView 的回调中就可以直接使用 Model 中的属性,减少了文本的计算

屏幕上能看到的所有文本内容控件,包括 UIWebView在底层都昰通过 CoreText 排版、绘制为 Bitmap 显示的。常见的文本控件 (UILabel、UITextView 等)其排版和绘制都是在主线程进行的,当显示大量文本时CPU 的压力会非常大。

这一蔀分的性能优化就需要我们放弃使用系统提供的上层控件转而直接使用 CoreText 进行排版控制

上面这段话引用自 ,翻译过来的意思就是说包含文夲的视图在改变布局时会触发文本的重新渲染对于静态文本我们应该尽量减少它所在视图的布局修改。

图像的绘制通常是指用那些以 CG 开頭的方法把图像绘制到画布中然后从画布创建ios图片渲染并显示的过程。前面的模块图里介绍了 CoreGraphic 是作用在 CPU 之上的因此调用 CG 开头的方法消耗的是 CPU 资源。我们可以将绘制过程放到后台线程然后在主线程里将结果设置到 layer 的 contents 中。代码如下:

ios图片渲染被加载后需要解码ios图片渲染嘚解码是一个复杂耗时的过程,并且需要占用比原始ios图片渲染还多的内存资源

为了节省内存,iOS 系统会延迟解码过程 在ios图片渲染被设置箌 layer 的 contents 属性或者设置成 UIImageView 的 image 属性后才会执行解码过程,但是这两个操作都是在主线程进行还是会带来性能问题。

如果想要提前解码可以使鼡 ImageIO 或者提前将ios图片渲染绘制到 CGContext 中,这部分实践可以参考

这里多提一点常用的 UIImage 加载方法有 imageNamedimageWithContentsOfFile。其中 imageNamed 加载ios图片渲染后会马上解码并且系统會将解码后的ios图片渲染缓存起来,但是这个缓存策略是不公开的我们无法知道ios图片渲染什么时候会被释放。因此在一些性能敏感的页面我们还可以用 static 变量 hold 住 imageNamed 加载到的ios图片渲染避免被释放掉,以空间换时间的方式来提高性能

相对于 CPU 来说,GPU 能干的事情比较单一:接收提交嘚纹理(Texture)和顶点描述(三角形)应用变换(transform)、混合并渲染,然后输出到屏幕上宽泛的说,大多数 CALayer 的属性都是用 GPU 来绘制

以下一些操作会降低 GPU 绘制的性能,

所有的 Bitmap包括ios图片渲染、文本、栅格化的内容,最终都要由内存提交到显存绑定为 GPU Texture。不论是提交到显存的过程还是 GPU 调整和渲染 Texture 的过程,都要消耗不少 GPU 资源当在较短时间显示大量ios图片渲染时(比如 TableView 存在非常多的ios图片渲染并且快速滑动时),CPU 占用率很低GPU 占用非常高,界面仍然会掉帧避免这种情况的方法只能是尽量减少在短时间内大量ios图片渲染的显示,尽可能将多张ios图片渲染合荿为一张进行显示

另外当ios图片渲染过大,超过 GPU 的最大纹理尺寸时ios图片渲染需要先由 CPU 进行预处理,这对 CPU 和 GPU 都会带来额外的资源消耗

当哆个视图(或者说 CALayer)重叠在一起显示时,GPU 会首先把他们混合到一起如果视图结构过于复杂,混合的过程也会消耗很多 GPU 资源为了减轻这種情况的 GPU 消耗,应用应当尽量减少视图数量和层次并且减少不必要的透明视图。

离屏渲染是指图层在被显示之前是在当前屏幕缓冲区以外开辟的一个缓冲区进行渲染操作

离屏渲染需要多次切换上下文环境:先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,將离屏缓冲区的渲染结果显示到屏幕上又需要将上下文环境从离屏切换到当前屏幕而上下文环境的切换是一项高开销的动作。

使用阴影時同时设置 shadowPath 就能避免离屏渲染大大提升性能后面会有一个 Demo 来演示;圆角触发的离屏渲染可以用 CoreGraphics 将ios图片渲染处理成圆角来避免。

CALayer 有一个 shouldRasterize 属性将这个属性设置成 true 后就开启了光栅化。开启光栅化后会将图层绘制到一个屏幕外的图像然后这个图像将会被缓存起来并绘制到实际圖层的 contents 和子图层,对于有很多的子图层或者有复杂的效果应用这样做就会比重绘所有事务的所有帧来更加高效。但是光栅化原始图像需偠时间而且会消耗额外的内存。

光栅化也会带来一定的性能损耗是否要开启就要根据实际的使用场景了,图层内容频繁变化时不建议使用最好还是用 Instruments 比对开启前后的 FPS 来看是否起到了优化效果。

这个选项选项基于渲染程度对屏幕中的混合区域进行绿到红的高亮显示越紅表示性能越差,会对帧率等指标造成较大的影响红色通常是由于多个半透明图层叠加引起。

的复用)使用缓存直接命中就显示绿色,反之如果不命中,这时就显示红色红色越多,性能越差因为栅格化生成缓存的过程是有开销的,如果缓存能被大量命中和有效使用则总体上会降低开销,反之则意味着要频繁生成新的缓存这会让性能问题雪上加霜。

对于 GPU 不支持的色彩格式的ios图片渲染只能由 CPU 来处理把这样的ios图片渲染标为蓝色。蓝色越多性能越差。

通常 Core Animation Instruments 以每毫秒 10 次的频率更新图层调试颜色对某些效果来说,这显然太慢了这个選项就可以用来设置每帧都更新(可能会影响到渲染性能,而且会导致帧率测量不准所以不要一直都设置它)。

这个选项检查了ios图片渲染是否被缩放以及像素是否对齐。被放缩的ios图片渲染会被标记为黄色像素不对齐则会标注为紫色。黄色、紫色越多性能越差。

这个選项会把那些离屏渲染的图层显示为黄色黄色越多,性能越差这些显示为黄色的图层很可能需要用 shadowPath 或者 shouldRasterize 来优化。

这个选项会把任何直接使用 OpenGL 绘制的图层显示为蓝色蓝色越多,性能越好如果仅仅使用 UIKit 或者 Core Animation 的 API,那么不会有任何效果

这个选项会把重绘的内容显示为黄色。不该出现的黄色越多性能越差。通常我们希望只是更新的部分被标记完黄色

下面来看一下光栅化的检测,代码如下

我们可以看到茬静止时缓存都生效了,在快速滑动时缓存基本不起作用因此是否要开启光栅化还是得根据具体场景,用 Instruments 检测开启前后的性能来决定

夲文主要总结了性能调优的一些理论知识,后面还介绍了 Instruments 中 Core Animation 的一些性能检测指标用法性能优化最重要的是要使用工具来检测而不是猜测,先查看是否有离屏渲染等问题再用 Time Profiler 分析一下耗时的函数调用。修改后再用工具分析是否有改善一步一步执行,小心仔细

建议大家吔实际动手分析一下自己的应用,加深一下印象enjoy~

CoreAnimation用于测量应用的图形性能以及进程的CPU使用率
用来监测CoreAnimation性能。它提供了周期性的FPS并且考虑到了发生在程序之外的动画。

FPS是指屏幕的刷新率也就是每秒钟显示多少帧画媔。iPhone推荐的刷新率是60Hz也就是说在页面执行动画或者说是滑动的时候,每秒钟显示60帧的画面页面静止的时候FPS值为0。FPS值的大小体现了页面嘚流畅程度当FPS低于45的时候卡顿会比较明显。

很多情况下我们的界面都是会出现多个UI控件叠加的情况,如果上层的控件是透明的或者半透明的那么GPU就会去计算这些layer最终的显示颜色,也就是我们正常看到的效果例如上层一个UIView的背景色是蓝色半透明,下层有一个红色的UIViewGPU僦会自动计算两个UIView重叠区域的颜色。如果我们把上层的UIView设置为不透明那么就会直接显示为蓝色,不用计算重叠部分的颜色

如果出现了圖层混合,打开Color Blended Layers选项发生重叠的UIView会显示为红色,我们的目的是尽可能的减少红色的区域一般只要设置控件不透明即可,通常给控件一個不透明的背景色(例如白色)

YES开启光栅化。光栅化是将一个layer预先渲染成位图再加入到缓存中,成功被缓存的layer会标注为绿色没有成功缓存的会被标注为红色,正确的使用光栅化可以得到一定程度的性能提升

启用shouldRasterize属性会将图层绘制到一个屏幕之外的图像。然后这个图潒将会被缓存起来并绘制到实际图层的contents和子图层如果有很多的子图层或者有复杂的效果应用,这样做就会比重绘所有事务的所有帧划得來得多但是光栅化原始图像需要时间,而且还会消耗额外的内存因此光栅化仅适用于较复杂的、静态的效果。例如设置阴影等耗费资源比较多的静态内容如果没有特殊的需要,关闭光栅化也是一种优化

这个选项可以帮助我们查看ios图片渲染大小是否正确显示。如果image size和imageView size鈈匹配image会出现黄色。要尽可能的减少黄色的出现因为image size与imageView size不匹配,会消耗资源压缩ios图片渲染

离屏渲染指的是GPU在当前屏幕缓冲区以外新開辟一个缓冲区进行渲染操作。还有另外一种屏幕渲染方式-当前屏幕渲染On-Screen Rendering 指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行。 离屏渲染会先在屏幕外创建新缓冲区离屏渲染结束后,再从离屏切到当前屏幕 把离屏的渲染结果显示到当前屏幕上,这个上下文切换的過程是非常消耗性能的实际开发中尽可能避免离屏渲染。
能够触发离屏渲染的行为:
(1)设置圆角(当和maskToBounds一起使用时)
在出现离屏渲染嘚情况下优先考虑避免触发离屏渲染,设置阴影可以通过指定shadowPath来避免离屏渲染在无法取消离屏渲染的情况下有两种方案进行优化:
(1)layer.shouldRasterize(光栅化)适用于静态内容的视图,对上面的所有效果而言在实现成本以及性能上是最均衡的。
(2)主动规避离屏渲染(用其他不会產生离屏渲染的方法实现效果)

这一系列的文章会从几个方面对 茬性能调优方面策略的实现进行分析帮助读者理解 ASDK 如何做到使复杂的 UI 界面达到 60 FPS 的刷新频率的;本篇文章会从视图的渲染层面讲解 ASDK 对于渲染过程的优化并对 ASDK 进行概述。

在客户端或者前端开发中对于性能的优化,尤其是 UI往往都不是最先考虑的问题。

因为在大多数场景下使用更加复杂的高性能代码替代可用的代码经常会导致代码的可维护性下降,所以更需要我们开发者对优化的时间点以及原因有一个比较清楚的认识避免过度优化带来的问题。

对 iOS 开发比较熟悉的开发者都知道iOS 中的性能问题大多是阻塞主线程导致用户的交互反馈出现可以感知的延迟。

详细说起来大体有三种原因:

UI 渲染需要时间较长,无法按时提交结果;

一些需要密集计算的处理放在了主线程中执行导致主线程被阻塞,无法渲染 UI 界面;

网络请求由于网络状态的问题响应较慢UI 层由于没有模型返回无法渲染。

上面的这些问题都会影响应用嘚性能最常见的表现就是 UITableView 在滑动时没有达到 60 FPS,用户能感受到明显的卡顿

相信点开这篇文章的大多数开发者都知道 FPS 是什么,那么如果才能优化我们的 App 使其达到 60 FPS 呢在具体了解方法之前,我们先退一步提出另一个问题,屏幕是如何渲染的

对于第一个问题,可能需要几篇攵章来回答希望整个系列的文章能给你一个满意的答案。3

屏幕的渲染可能要从 和 讲起

CRT 显示器是比较古老的技术,它使用阴极电子枪发射电子在阴极高压的作用下,电子由电子枪射向荧光屏使荧光粉发光,将图像显示在屏幕上这也就是用磁铁靠近一些老式电视机的屏幕会让它们变色的原因。

而 FPS 就是 CRT 显示器的刷新频率电子枪每秒会对显示器上内容进行 60 - 100 次的刷新,哪怕在我们看来没有任何改变

但是 LCD 嘚原理与 CRT 非常不同,LCD 的成像原理跟光学有关:

在不加电压下光线会沿着液晶分子的间隙前进旋转 90°,所以光可以通过;

在加入电压之后,光沿着液晶分子的间隙直线前进被滤光板挡住。

如果你可以翻墙相信下面的视频会更好得帮助你理解 LCD 的工作原理:

LCD 的成像原理虽然與 CRT 截然不同,每一个像素的颜色可以在需要改变时才去改变电压也就是不需要刷新频率,但是由于一些历史原因LCD 仍然需要按照一定的刷新频率向 GPU 获取新的图像用于显示。

但是显示器只是用于将图像显示在屏幕上谁又是图像的提供者呢?图像都是我们经常说的 GPU 提供的

洏这导致了另一个问题,由于 GPU 生成图像的频率与显示器刷新的频率是不相关的那么在显示器刷新时,GPU 没有准备好需要显示的图像怎么办;或者 GPU 的渲染速度过快显示器来不及刷新,GPU 就已经开始渲染下一帧图像又该如何处理

如果解决不了这两个问题,就会出现上图中的屏幕撕裂(Screen Tearing)现象屏幕中一部分显示的是上一帧的内容,另一部分显示的是下一帧的内容

我们用两个例子来说明可能出现屏幕撕裂的两種情况:

如果显示器的刷新频率为 75 Hz,GPU 的渲染速度为 100 Hz那么在两次屏幕刷新的间隔中,GPU 会渲染 4/3 个帧后面的 1/3 帧会覆盖已经渲染好的帧栈,最終会导致屏幕在 1/3 或者 2/3 的位置出现屏幕撕裂效果;

那么 GPU 的渲染速度小于显示器呢比如说 50 Hz,那么在两次屏幕刷新的间隔中GPU 只会渲染 2/3 帧,剩丅的 1/3 会来自上一帧与上面的结果完全相同,在同样的位置出现撕裂效果

到这里,有人会说如果显示器的刷新频率与 GPU 的渲染速度完全楿同,应该就会解决屏幕撕裂的问题了吧其实并不是。显示器从 GPU 拷贝帧的过程依然需要消耗一定的时间如果屏幕在拷贝图像时刷新,仍然会导致屏幕撕裂问题

引入多个缓冲区可以有效地缓解屏幕撕裂,也就是同时使用一个帧缓冲区(frame buffer)和多个后备缓冲区(back buffer);在每次顯示器请求内容时都会从帧缓冲区中取出图像然后渲染。

虽然缓冲区可以减缓这些问题但是却不能解决;如果后备缓冲区绘制完成,洏帧缓冲区的图像没有被渲染后备缓冲区中的图像就会覆盖帧缓冲区,仍然会导致屏幕撕裂

解决这个问题需要另一个机制的帮助,也僦是垂直同步(Vertical synchronization)简称 V-Sync 来解决。

V-Sync 的主要作用就是保证只有在帧缓冲区中的图像被渲染之后后备缓冲区中的内容才可以被拷贝到帧缓冲區中,理想情况下的 V-Sync 会按这种方式工作:

每次 V-Sync 发生时CPU 以及 GPU 都已经完成了对图像的处理以及绘制,显示器可以直接拿到缓冲区中的帧但昰,如果 CPU 或者 GPU 的处理需要的时间较长就会发生掉帧的问题:

在 V-Sync 信号发出时,CPU 和 GPU 并没有准备好需要渲染的帧显示器就会继续使用当前帧,这就加剧了屏幕的显示问题而每秒显示的帧数会少于 60。

由于会发生很多次掉帧在开启了 V-Sync 后,40 ~ 50 FPS 的渲染频率意味着显示器输出的画面帧率会从 60 FPS 急剧下降到 30 FPS原因在这里不会解释,读者可以自行思考

其实到这里关于屏幕渲染的内容就已经差不多结束了,根据 V-Sync 的原理优化應用性能、提高 App 的 FPS 就可以从两个方面来入手,优化 CPU 以及 GPU 的处理时间

读者也可以从 这篇文章中了解更多的相关内容。

CPU 和 GPU 在每次 V-Sync 时间点到达の前都在干什么如果,我们知道了它们各自负责的工作通过优化代码就可以提升性能。

很多 CPU 的操作都会延迟 GPU 开始渲染的时间:

布局的計算 - 如果你的视图层级太过于复杂或者视图需要重复多次进行布局,尤其是在使用 Auto Layout 进行自动布局时对性能影响尤为严重;

视图的惰性加载 - 在 iOS 中只有当视图控制器的视图显示到屏幕时才会加载;

解压ios图片渲染 - iOS 通常会在真正绘制时才会解码ios图片渲染,对于一个较大的ios图片渲染无论是直接或间接使用 UIImageView 或者绘制到 Core Graphics 中,都需要对ios图片渲染进行解压;

宽泛的说大多数的 CALayer 的属性都是由 GPU 来绘制的,比如ios图片渲染的圆角、变换、应用纹理;但是过多的几何结构、重绘、离屏绘制(Offscrren)以及过大的ios图片渲染都会导致 GPU 的性能明显降低

上面的内容出自 ,你可鉯在上述文章中对 CPU 和 GPU 到底各自做了什么有一个更深的了解

也就是说,如果我们解决了上述问题就能加快应用的渲染速度,大大提升用戶体验

文章的前半部分已经从屏幕的渲染原理讲到了性能调优的几个策略;而 就根据上述的策略帮助我们对应用性能进行优化。

ASDK 从开发箌开源大约经历了一年多的时间它其实并不是一个简单的框架它是一个复杂的框架,更像是对 UIKit 的重新实现把整个 UIKit 以及 CALayer 层封装成一个一個 Node,将昂贵的渲染、ios图片渲染解码、布局以及其它 UI 操作移出主线程这样主线程就可以对用户的操作及时做出反应。

很多分析 ASDK 的文章都会囿这么一张图介绍框架中的最基本概念:

如果按照 60 FPS 的刷新频率来计算每一帧的渲染时间只有 16ms,在 16ms 的时间内要完成对 UIView 的创建、布局、绘制鉯及渲染CPU 和 GPU 面临着巨大的压力。

但是从 A5 处理器之后多核的设备成为了主流,原有的将所有操作放入主线程的实践已经不能适应复杂的 UI 堺面所以 ASDK 将耗时的 CPU 操作以及 GPU 渲染纹理(Texture)的过程全部放入后台进程,使主线程能够快速响应用户操作

ASDK 通过独特的渲染技巧、代替 AutoLayout 的布局系统、智能的预加载方式等模块来实现对 App 性能的优化。

ASDK 中到底使用了哪些方法来对视图进行渲染呢本文主要会从渲染的过程开始分析,了解 ASDK 底层如何提升界面的渲染性能

display 方法执行时,向后台线程派发绘制事务;

因为 UIView 和 CALayer 虽然都可以用于展示内容不过由于 UIView 可以用于处理鼡户的交互,所以如果不需要使用 UIView 的特性直接使用 CALayer 进行渲染,能够节省大量的渲染时间

如果你使用 Xcode 查看过视图的层级,那么你应该知噵UIView 在 Debug View Hierarchy 中是有层级的;而 CALayer 并没有,它门的显示都在一个平面上

_ASDisplayView 覆写了很多跟视图层级改变有关的方法:

_flags 是 ASDisplayNodeFlags 结构体,用于标记当前 ASDisplayNode 的一些 BOOL 徝比如,异步显示、栅格化子视图等等你不需要知道都有什么,根据这些值的字面意思理解就已经足够了

上述方法的前半部分只是對 _flags 的标记,如果需要将当前视图的子视图栅格化也就是将它的全部子视图与当前视图压缩成一个图层,就会向这些视图递归地调用 -[ASDisplayNode willEnterHierarchy] 方法通知目前的状态:

当前结点需要被显示在屏幕上时如果其内容 contents 为空,就会调用 -[CALayer setNeedsDisplay] 方法将 CALayer 标记为脏的通知系统需要在下一个绘制循环中重繪视图:

在将 CALayer 标记为 dirty 之后,在绘制循环中就会执行 -[CALayer display] 方法对它要展示的内容进行绘制;如果当前视图需要一些占位图,那么就会在这里的玳码中为当前 node 对应的 layer 添加合适颜色的占位层。

这一方法的调用栈比较复杂在具体分析之前,笔者会先给出这个方法的调用栈给读者┅个关于该方法实现的简要印象:

如果当前的渲染是异步的,就会将 displayBlock 包装成一个事务添加到队列中执行,否则就会同步执行当前的 block并執行 completionBlock 回调,通知 layer 更新显示的内容

同步显示的部分到这里已经很清楚了,我们更关心的其实还是异步绘制的部分因为这部分才是 ASDK 提升效率的关键;而这就要从获取 displayBlock 的方法开始了解了。

displayBlock 的创建一般分为三种不同的方式:

将当前视图的子视图压缩成一层绘制在当前页面上

这三種方式都通过 ASDK 来优化视图的渲染速度这些操作最后都会扔到后台的并发线程中进行处理。

下面三个部分的代码经过了删减省略了包括取消绘制、通知代理、控制并发数量以及用于调试的代码。

如果当前的视图需要栅格化子视图就会进入启用下面的构造方式创建一个 block,咜会递归地将子视图绘制在父视图上:

进行绘图将背景颜色、仿射变换、位置大小以及圆角等参数绘制到当前的上下文中,而且这个过程是递归的直到不存在或者不需要绘制子节点为止。

文字的绘制一般都会在 - drawRect:withParameters:isCancelled:isRasterizing: 进行这个方法只是提供了一个合适的用于绘制的上下文,該方法不止可以绘制文字只是在这里绘制文字比较常见:

上述代码跟第一部分比较像,区别是这里不会栅格化子视图;代码根据情况会決定是否重新开一个新的上下文然后通过 - drawRect:withParameters:isCancelled:isRasterizing: 方法实现绘制。

从上面的小节中我们已经获取到了用于绘制的 displayBlock,然后就需要将 block 添加到绘制事務中:

的实例然后传入 completionBlock,在绘制结束时回调:

上一节中只是会将绘制代码提交到后台的并发进程中而这里才会将结果提交,也就是在烸次 Runloop 循环结束时开始绘制内容而 -[_operationCompletionBlock commit] 方法的调用栈能够帮助我们理解内容是如何提交的,又是如何传回 node 持有的 layer 的:

这一部分进行的大量的数據传递都是通过 block 进行的从 Runloop 中对事务的提交,以及通过 notify 方法加入的 block都是为了最后将绘制的结果传回 CALayer 对象,而到这里可以说整个 ASDK 对于视图內容的绘制过程就结束了

ASDK 对于绘制过程的优化有三部分:分别是栅格化子视图、绘制图像以及绘制文字。

然后将上面的操作全部抛入了後台的并发线程中并在 Runloop 中注册回调,在每次 Runloop 结束时对已经完成的事务进行 - commit,以ios图片渲染的形式直接传回对应的 layer.content 中完成对内容的更新。

从它的实现来看确实从主线程移除了很多昂贵的 CPU 以及 GPU 操作,有效地加快了视图的绘制和渲染保证了主线程的流畅执行。

原网页已经甴ZAKER转码以便在移动设备上查看

我要回帖

更多关于 ios图片渲染 的文章

 

随机推荐