美文网首页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 内存暴增原因,如何优化绘图

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

  • 关于drawRect内存暴增

    关于drawRect内存暴增的总结,在新建的view里重写了- (void)drawRect:(CGRect)re...

  • UIGraphicsGetImageFromCurrentIma

    绘图操作还原时内存暴增 目前在做绘图板,每画一笔需要生成一张图片然后销毁, 这时生成图片的内存是没有问题的, 但...

  • iOS开发之drawRect内存优化

    文章预读 内存恶鬼drawRect - 谈画图功能的内存优化 根据文中提到的解决内存问题有这重要的两点:①尽量不用...

  • iOS autoreleasepool

    一般当有处理大量临时对象时,如果不注意会造成内存暴增,可以使用 autoreleasepool 进行优化 一下代码...

  • iOS中图片的解压缩

    使用SDWebImage下载高分辨率图,导致内存暴增。 再进一步定位问题,发现内存暴增的罪魁祸首是SDWebIma...

  • drawRect:绘图

    drawRect:绘图 作用:专门用来绘图 什么时候调用:当View显示的时候调用(ViewWillAppear和...

  • UIView之setNeedsDisplay和setNeedsL

    setNeedsDisplay方便绘图其实最终调用的是drawRect方法1.drawRect是在viewDIdL...

  • iOS CAShapeLayer+UIBezierPath设置k

    最近在写一个类似画板的需求。 功能实现参考文章:内存恶鬼drawRect - 谈画图功能的内存优化 功能实现参考D...

  • jvm优化案例2--并发高时请求规律性超时

    现象 线上公开课系统,由于疫情原因,访问暴增。系统优化以后,读请求,单机请求qps=1500左右。但是在线上业务繁...

网友评论

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

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