iOS Core Animation - Advanced Techniques-学习笔记(五)

iOS Core Animation - Advanced Techniques-学习笔记(五),第1张

《iOS Core Animation: Advanced Techniques》- 性能调优篇

当我们想开发一个基于时间流逝运动的动画时,首先会想到使用NSTimer计时器,但是这里不推荐使用这个类,我们看下NSTimer是怎么工作的。

iOS上每个线程都管理一个Runloop。对于主线程的Runloop,每一次循环都会做以下 *** 作:

当设置了一个NSTimer计时器,这个任务会被插入任务队列中,但是它只会在上一个任务完成之后开始执行。这通常会导致有几毫秒的延迟,但是如果上一个任务过了很久才完成就会导致延迟很长一段时间。

我们可以通过一些途径来优化:

CADisplayLink和NSTimer的接口很相似,但是和NSTimer用秒作为及时单位不同,它使用属性 frameInterval 指定间隔多少帧后执行,用CADisplayLink而不是NSTimer,会保证帧率足够连续,使得动画看起来更加平滑。

但要知道即使CADisplayLink也不能保证每一帧都按计划执行,一些失去控制的离散任务或者事件(例如资源紧张的后台程序,GPU渲染进程)可能会导致动画偶尔地丢帧。

添加到Runloop的任务都有一个指定优先级的模式,为了保证用户界面保持平滑,iOS会提供和用户界面相关任务的优先级,而且当UI很活跃的时候的确会暂停一些别的任务。

一个典型的例子就是当是用UIScrollview滑动的时候,重绘滚动视图的内容会比别的任务优先级更高,所以标准的NSTimer和网络请求就不会启动。

我们可以同时加入NSDefaultRunLoopMode和UITrackingRunLoopMode来保证动画不会被滑动或者其他IO行为打断

动画和屏幕上组合的图层实际上被一个单独的进程管理,而不是你的应用程序。这个进程我们称它为渲染服务。在iOS5之前叫SpringBoard(同时管理着iOS的主屏),在iOS6之后叫做BackBoard。

Core Animation运行一段动画的过程:

CPU处理:

GPU处理:

所以我们真正能控制和优化的,只有在CPU处理布局和显示阶段,但是我们提交到IPC的渲染行为是可以被优化的,下面介绍CPU行为上的优化方法

视图布局计算会消耗掉部分时间,特别是使用AutoLayout。以60FPS作为一个iOS流畅度的黄金标准,那么将要求布局在00166667s内完成,而AutoLayout基于Cassowary算法会计算大量线性等式和不等式,下图(来自互联网)做了一个简单的布局对比,当视图数达到50个,AutoLayout将会出现性能瓶颈。Facebook的 yoga 框架允许你在iOS开发中使用FlexBox布局,同样来自Facebook的 AsyncDisplayKit 框架也引入了FlexBox优化布局的性能开销

懒加载只有在视图需要加载时才会去加载,这样的做法对内存占用和启动速度都要好处,但是在完成初始化 *** 作前,你的动画都会被延迟。所以可以对动画必要视图进行优先初始化,而非傻傻的懒加载

当实现了视图中的 -drawRect: 方法,或者CALayerDelegate的 -drawLayer:inContext: 方法,就会在绘制前产生一个可估算的性能开销,CoreAnimation需要在内存中开辟一个等大小的寄宿图用于绘制,CoreGraphics绘制会十分缓慢,绘制结束还需通过通过IPC将数据上传到BackBoard,这也是为什么非不得已都不建议使用软件绘图,并且不要实现 -drawRect: 方法,尽管可能它是空方法。CoreAniamtion为图形绘制提供了专有图层,并提供了硬件加速,总体上都比Core Graphics更快,同时他们也避免了创造一个寄宿图

PNG或者JPEG压缩之后的文件会比同质量的位图小得多,直接或间接使用UIImageView,或者将绘制到CoreGraphics都需要对解压缩,对于一个较大的,都会占用一定的时间。这一步虽然不可避免,但是我们可以把这个 *** 作放到后台线程,先把绘制到CGBitmapContext中,然后从Bitmap直接创建。

主流的网络库都用了这样的方式,我们来看下SDWebImage的网络Res解析类,在获取到网络资源后,直接在子线程对绘制解码:

之前我们说过,CoreGraphic绘图是有较大性能开销的,那么如果一定要使用软件绘图,那么我们在封装的时候,可以提供同步和异步的绘制方法,非常幸运,CoreGraphic提供的方法都是线程安全的,例如提供一个绘制色块的方法

有时候要用CAShapeLayer并不能完全代替CoreGraphics,比如创建一个绘图应用时。当我们绘制的轨迹越复杂,绘制的越多,就会越卡顿,帧数将会下降。这是由于每次移动手指绘制时,都会重绘之前的轨迹,即使场景大部分都没有改变

为了减少不必要的绘制,Mac OS和iOS设备将会把屏幕区分为需要重绘的区域和不需要重绘的区域。那些需要重绘的部分被称作「脏区域」。在实际应用中,鉴于非矩形区域边界裁剪和混合的复杂性,通常会区分出包含指定视图的矩形位置,而这个位置就是「脏矩形」,如果你可以高效确定指定系统需要重绘的脏矩形位置,那么可以调用 -setNeedsDisplayInRect: 来避免不必要的绘制而非调用 -setNeedsDisplay 。

这里有一个例子,例如当我们创建了一个画笔,触碰屏幕则会将画笔size的矩形绘制到图层上,由于我们明确知道画笔的尺寸,那么在用户绘制时每次拖拽所产生的「脏矩形」我们都是可以准确计算的,然后告诉GPU我们只需要重绘画笔矩形而非重绘整个画布

GPU会放弃绘制那些完全被其他图层遮挡的像素,但是要计算出一个图层是否被遮挡也是相当复杂并且会消耗处理器资源。同样,重叠多个透明视图(图层)消耗的资源也是相当客观的。所以为了加速处理进程,不到必须时刻不要使用透明图层。任何情况下,你应该这样做:

这样做可以使计算过程加速,在CPU处理阶段,Core Animation就可以处理好并抛弃那些完全被遮盖的图层

当图层被指定为在未预合成之前不能直接在屏幕中绘制时,离屏渲染会被唤醒,这意味着图层必须在被显示之前在一个屏幕外上下文中被渲染,而对于GPU来说,这样的 *** 作对性能是有较大损耗的。

会产生离屏渲染的 *** 作:

例如当一个列表视图中出现大量圆角视图快速滑动时,可以观察到GPU资源已经占满,而CPU资源消耗很少。这是由于CPU已经计算完所有图层信息提交IPC,而GPU负担了大量的离屏渲染任务

优化的方案首先是避免圆角和 maskToBounds 一起使用,非必须不适用图层蒙版,若无法避免那么就将性能开销转嫁给CPU

这里有几种处理方式,一种是对于需要切圆角的,不要使用 CALayercorner 在图层上裁剪,而是在获取到资源后在子线程提交前再进行一次对裁切的异步绘制;第二种使用图层栅格化 CALayershouldRasterize 转化为位图

用代码判断吗。代码有很多种,说思路。 用网络请求从网址下过来是NSData。 如果NSData为空或不能转化成,就就是空啊。 你也可以把这个交给SDWebImage 或是 EGOImage的第三方管理类。大多数情况下可以用这些第三方管理类,他们运作良好。 除非你要自己管理的存储和命名。

每一个格式都有对应的十六进制数据(PS:当然十六进制也是从二进制转换过来的),也可以说就是这些十六进制数据组成了一张,然后再通过计算机内部的渲染等一系列算法从而显示了一张,而往往前面的4~8个字节往往都代表了这张的格式

NSData+ImageContentTypeh 的头文件夹下有这么一个方法

uint8_t c;

[data getBytes:&c length:1];

这直接就截取了前1个字节长度的数据

再判断每个字节中的十六进制数所对应的格式

case 0x89: return SDImageFormatPNG;

我使用SDWebImage的图像在UICollectionView中我的 iOS 应用程序的缓存。

一切都很好,但是当用户滚动快速的集合视图有总是小暂停之前占位符将被替换缓存的图像。我相信这是因为缓存中检查。为更好的用户体验,我想要显示正确的图像,而不是占位符,一旦图像实际上的高速缓存的单元格。如果我能得到的缓存的图像 (设备) 本地文件系统路径并将它存储在该显示的实例,并使用它,这将很容易 (如果存在) 而不是我的占位符。

然而它获取的唯一论据是UIImage实例 (实际上也有BOOL变量称为缓存太正在传递的主分支) 中有向传递给setImageWithURL方法成功块的可能性。所以-有没有可能直接从UIImage实例获取图像的文件系统路径或我应该修改SDWebImage所以它传递的信息

以上就是关于iOS Core Animation - Advanced Techniques-学习笔记(五)全部的内容,包括:iOS Core Animation - Advanced Techniques-学习笔记(五)、iOS 怎样通过图片网址,判断图片是不是空、iOS面试题--SDWebImage 是如何判断图片格式的原理等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9298595.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-26
下一篇2023-04-26

发表评论

登录后才能评论

评论列表(0条)

    保存