如何解决CALayer的contents内存暴增问题

前两天QQ群大佬提出一个问题,如何解决CALayer的contents属性赋值之后的内存暴增问题,百度了一下无头绪,偶然看到了唐巧的文章,感觉很有意思,特此记录一下。原文在此:内存恶鬼drawRect - 谈画图功能的内存优化

正文:

先来说一下contens是个啥东西:CoreAnimation:CALayer的contents
唐巧文章里写的很清楚了,在这里不再过多的赘述,大概是这样的:

  1. 搞了一个简易功能的画板,记录手指触摸的轨迹然后绘制在屏幕上。
  2. 发现两个问题:当画板弹出,其余无任何操作时,内存激增,然后当手指绘制开始时,内存又激增。
  3. 分析原因可能有两个:一是在手指绘制的过程中创建的大量点对象没有及时释放或者其他资源没有及时释放。这一点因为工程为ARCInstruments工具得以排除。二是系统在绘制过程中开始大量消耗内存,但是明显可以发现是画板创建之后就会有内存激增,所以矛头直指drawRect
    这是画板绘制功能的一段代码:
- (void)drawRect:(CGRect)rect
{
    if (!self.paths.count) return;
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    for (BHBPaintPath *path in self.paths) {
      CGContextSaveGState(ctx);
      [[UIColor blackColor] set];
      [path stroke]; // 关键的一步绘制
      CGContextRestoreGState(ctx);
    }
}
  1. 分析为何drawRect会出现内存暴增的真正原因:
    简单来说,咱们所看到的屏幕上的东西,其实都是一张图片,是由CALayercontents属性掌管着,最终图形渲染落点落在了contents身上。
  2. contents也被称为寄宿图,除了给它赋值CGImage以外,我们也可以直接对它进行绘制,绘制的方法正式此次问题的关键,通过集成UIView并实现-drawRect:方法即可自定义绘制。-drawRect:方法没有默认的实现,因此对UIView来说,寄宿图并不是必须的,UIView不关心绘制的内容。如果UIView检测到-drawRect:方法被调用了,他就会为视图分配一个寄宿图,这个寄宿图的像素尺寸等于视图大小乘以contentsScale(这个属性与屏幕分辨率有关,我们的画板程序在不同模拟器下呈现的内存用量不同也是因为它)的值。
    那么我们重回画板程序,当画板从屏幕上出现的时候,因为重写了-drawRect:方法,-drawRect:方法就会自动调用。生成一张寄宿图后,方法里面的代码利用Core Graphics去绘制n条黑色的线,然后 内容就会缓存起来,等待下次你调用-setNeedsDisplay时再进行更新。
    画板视图的-drawRect:方法的背后实际上都是底层的CALayer进行了重绘和保存中间产生的图片,CALayerdelegate属性默认实现了CALyaerDelegate协议,当它需要内容信息的时候回调用协议中的方法来拿。当画板重绘时,因为他的支持图层CALayer的代理就是画板视图的本身,所以支持图层会请求画板视图给它一个寄宿图来显示,它此刻会调用:
- (void)displayLayer:(CALayer *)layer;

如果画板试图实现了这个方法,就可以拿到layer来直接设置contents寄宿图,如果这个方法没有实现,支持图层CALayer会尝试调用:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;

这个方法调用之前,CALayer创建了一个合适尺寸的空寄宿图(尺寸由boundscontentsScale决定)和一个Core Graphics的绘制山下文环境,为绘制寄宿图做准备,它作为ctx参数传入。在这一步生成的空寄宿图内存是相当巨大的,它就是本次内存问题的关键,一旦你实现了CALayerDelegate协议中的-drawLayer:inContext:方法或者UIView中的-drawRect:方法(其实就是前者的包装方法),图层就创建了一个绘制上下文,这个上下文需要的内存可从这个公式得出:图层宽图层高4字节,宽高的单位均为像素。所以图层在每次绘制的时候都需要重新抹掉内存然后重新分配。它就是我们画板程序内存暴增的真正原因。

  1. 解决方法
    处理类似于画板这样画线条的需求直接用专用图层CAShapeLayer
    来看看这是个什么东西:
    CAShapeLayer是一个通过矢量图形而不是bitmap来绘制的图层子类。用CGPath来定义想要绘制的图形,CAShapeLayer会自动渲染。他可以完美替代我们直接使用Core Graphics绘制layer,相比之下使用CAShapeLayer有以下优点:
  • 渲染快速。CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。
  • 高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
  • 不会被图形边界剪裁掉。
  • 不会出现像素化。
  1. 总结一下绘制性能优化原则:
  • 绘制图形性能的优化最好的办法就是不去绘制。
  • 利用专有图层代替绘图需求。
  • 不得不用到的绘图尽量缩小试图面积,并且尽量降低重绘频率。
  • 异步绘制,推测内容,提前在其他线程绘制图片,在主线程中直接设置图片。
  1. 最后附上画板-demo
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容