美文网首页ios开发进阶iOS学习程序员
drawRect 内存暴增原因,如何优化绘图

drawRect 内存暴增原因,如何优化绘图

作者: JasonLee宸 | 来源:发表于2017-09-26 21:51 被阅读223次

    前言

    • 最近有朋友问,直接用UILabel和自己用drawRect画UILabel,哪个性能好?为什么?哪个占用的内存少?为什么?

    • 其实这种问题的本质就是使用drawRect会带来哪些问题,性能上当然是UILabel好了。

    drawRect

    每当我们需要绘图的时候,重写UIView的drawRect方法,在此方法中进行绘图操作,然后苹果要求我们调用UIView类中的setNeedsDisplay方法,系统就会自动调用drawRect。
    UIView继承于UIResponder,需要实现CALayerDelegate。此处我们不得不提出UIView和CALayer,每一个UIView 内部都有一个CALayer,UIView 的frame 直接返回的是layer的frame,在内容的绘制上其实是CALayer 操作的,所以绘图的关键还是在CALayer 上。那么CALayer 是如何显示在屏幕上的呢?

    image.png

    contents:对象提供的内容层,通常是CGImageRef,但也可能是其他。(Mac OS X 10.6及以后支持NSImage对象)默认值是零。
    CGImageRef,它是一个指向CGImage结构的指针。UIImage有一个CGImage属性,它返回一个”CGImageRef”,如果你想把这个值直接赋值给CALayer的contents,那你将会得到一个编译错误。因为CGImageRef并不是一个真正的Cocoa对象,而是一个Core Foundation类型。 尽管Core Foundation类型跟Cocoa对象在运行时貌似很像(被称作toll-free bridging),他们并不是类型兼容的,不过你可以通过bridged关键字转换。
    所以要为CALayer图层设置寄宿图片属性的最终代码:
    layer.contents = (__bridge id)image.CGImage;

    除了赋值之外,我们的绘图操作即是对contents(寄宿图)绘制。
    所以,回到问题,直接用UILabel和自己用drawRect画UILabel,哪个性能好?
    直接用UILabel,drawRect 方法没有默认实现,所以说,寄宿图也就不需要了。
    用drawRect绘图,默认实现CALayerDelegate协议

    image.png

    displayLayer:(CALayer *)layer; 可以通过此方法直接设置contents
    drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
    在此方法调用之前,CALayer需要创建一个空寄宿图(有尺寸)和一个Core
    Graphics 的CGContextRef(上下文),当绘制结束后,Core Animation打包所有图层和动画属性,然后通过IPC(内部处理通信)发送到渲染服务器进行显示,同时上下文会被不断渲染到屏幕上,直到下次调用setNeedsDisplay。
    所以每次重绘都需要抹掉内存重新分配,空寄宿图的产生就消耗了大量内存,这也就是drawRect 内存暴增原因。

    那么我们如果必须使用drawRect,如何优化绘图呢?
    Core Graphics框架 有强大的api,但是UIBezierPath 对paths进一步封装,使用更加简单,同时我们使用CAShapeLayer 才会使UIBezierPath发挥出更大的作用。
    CAShapeLayer继承自CALayer,可以使用CALayer的所有属性值。

    CAShapeLayer属于CoreAnimation框架,其动画渲染直接提交到手机的GPU当中,相较于view的drawRect方法使用CPU渲染而言(实现drawRect消耗性能跟CoreGraphics 这个框架是基于CPU没有关系),GPU图像处理工作更多在硬件层面,效率极高;

    一个 CAShapeLayer 不需要像普通 CALayer 一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。

    所以,以后关于绘图,我们可以尝试使用CAShapeLayer + UIBezierPath。

    参考:
    内存恶鬼drawRect - 谈画图功能的内存优化

    本文查阅多方资料整理,有误地方请指出,谢谢!

    相关文章

      网友评论

        本文标题:drawRect 内存暴增原因,如何优化绘图

        本文链接:https://www.haomeiwen.com/subject/hrurextx.html