备注:有很多很好的文章说把shouldRasterize(光栅化)个人认为应该按照PS里面专业术语来讲,个人理解。
不知道有没有小伙伴不知道这个字“栅”怎么读了,我特地百度了一下,有四种读法。
栅有四个读法:zhà,cè,shān,shi。
其详细解释为:
栅 [zhà]:用竹木铁条等做成的阻拦物:~栏。~子。
栅 [shān]:1.〔~极〕多极电子管靠阴极的一个电极。2.〔光~〕产生光的衍射图像的光学仪器。
栅 [shi]:〔上~〕〔下~〕地名,均在中国广东省。
栅格化(PS专业术语)
栅(shān)格化,是PS中的一个专业术语,栅格即像素,栅格化即将矢量图形转化为位图(栅格图像)。最基础的栅格化算法将多边形表示的三维场景渲染到二维表面。
位图
看到这个位图术语比较茫然,然后我问了一下我们公司的UI,才明白这个术语。
我的理解:图像没有被栅格化之前任意放大,都不会失帧。而栅格化化之后如果随着放大的倍数在增加,失帧会随着倍数的增加而增加。故:栅格化本身就是生成一个固定像素的图像。
1. 关于CALayer的shouldRasterize(栅格化)
@property BOOL shouldRasterize;
When true, the layer is rendered as a bitmap in its local coordinate space ("rasterized"), then the bitmap is composited into the destination (with the minificationFilter and magnificationFilter properties of the layer applied if the bitmap needs scaling). Rasterization occurs after the layer's filters and shadow effects are applied, but before the opacity modulation. As an implementation detail the rendering engine may attempt to cache and reuse the bitmap from one frame to the next. (Whether it does or not will have no affect on the rendered output.) When false the layer is composited directly into the destination whenever possible (however, certain features of the compositing model may force rasterization, e.g. adding filters). Defaults to NO.
使用阴影时同时设置 shadowPath 就能避免离屏渲染大大提升性能,但是使用不当也会造成性能的损耗。
CALayer 有一个 shouldRasterize 属性,将这个属性设置成 true 后就开启了光栅化。开启shouldRasterize后,CALayer会被栅格化为bitmap,layer的阴影等效果也会被保存到bitmap中,光栅化后会将图层绘制到一个屏幕外的图像,然后这个图像将会被缓存起来并绘制到实际图层的 contents 和子图层,对于有很多的子图层或者有复杂的效果应用,这样做就会比重绘所有事务的所有帧来更加高效。但是光栅化原始图像需要时间,而且会消耗额外的内存。
故:当我们开启栅格化后,需要注意4点问题。
1. 如果我们更新已栅格化的layer,会造成大量的offscreen渲染。
因此CALayer的栅格化选项的开启与否需要我们仔细衡量使用场景。只能用在图像内容不变的前提下的:
用于避免静态内容的复杂特效的重绘,例如前面讲到的UIBlurEffect
用于避免多个View嵌套的复杂View的重绘。
而对于经常变动的内容,这个时候不要开启,否则会造成性能的浪费。
例如我们日程经常打交道的TableViewCell,因为TableViewCell的重绘是很频繁的(因为Cell的复用),如果Cell的内容不断变化,则Cell需要不断重绘,如果此时设置了cell.layer可栅格化。则会造成大量的offscreen渲染,降低图形性能。
当然,合理利用的话,是能够得到不少性能的提高的,因为使用shouldRasterize后layer会缓存为Bitmap位图,对一些添加了shawdow等效果的耗费资源较多的静态内容进行缓存,能够得到性能的提升。
2. 不要过度使用,系统限制了缓存的大小为2.5X Screen Size.
如果过度使用,超出缓存之后,同样会造成大量的offscreen渲染。
3. 被栅格化的图片如果超过100ms没有被使用,则会被移除
因此我们应该只对连续不断使用的图片进行缓存。对于不常使用的图片缓存是没有意义,且耗费资源的。
4. 当 UIView.layer.shouldRasterize = YES 时,生成的位图会缓冲起来,如果TabelView 滑动的时候(UITableViewCell 复用)使用缓存直接命中,就显示绿色,反之,如果不命中,这时就显示红色。红色越多,性能越差.
图中有几个有趣的地方
1. 上下微小幅度滑动时,一直是绿色
2. 上下较大幅度滑动,新出现的label一开始是红色,随后变成绿色
3. 如果静止一秒钟,刚开始滑动时会变红。
这是因为layer进行栅格化后渲染成位图放在缓存中。当屏幕出现滑动时,我们直接从缓存中读取而不必渲染,所以会看到绿色。当新的label出现时,缓存中没有个这个label的位图,所以会变成红色。第三点比较关键,缓存中的对象有效期只有100ms,即如果在0.1s内没有被使用就会自动从缓存中清理出去。这就是为什么停留一会儿再滑动就会看到红色。
栅格化的缓存机制是一把双刃剑,先写入缓存再读取有可能消耗较多的时间。因此栅格化仅适用于较复杂的、静态的效果。通过Instrument的调试发现,这里使用光栅化经常出现未命中缓存的情况,
总结:如果View的Frame和Content不经常变化,开启shouldRasterize = YES ,反之则不要开启浪费性能,如果TableView滑动 Cell使用位图则是绿色,反之红色,绿色越多性能越好,红色反之。
参考:
What triggers “Color Copied Images” and “Color Hits Green and Misses Red” in Instruments?