iOS app性能相关

摘抄:iOS app性能优化的那些事

1、 instruments
2、 不要阻塞主线程
3、 使用cache
4、 减少程序启动过程中的任务
5、 使用合适的[数据结构]
6、懒加载view

分析图像动画性能主要用的是Core Animation这个组件,先简单介绍一下里面一些经常用到的选项:
Color Blended layers
标示混合的图层会为红色,不透明的图层为绿色,通常我们希望绿色的区域越多越好。
Color Hits Green and Misses Red
假如我们设置viewlayer的shouldRasterize为YES,那些成功被缓存的layer会标注为绿色,反之为红色,下面会有详细介绍。
Color copied images
标示那些被Core Animation拷贝的图片。这主要是因为该图片的色彩格式不能被GPU直接处理,需要在CPU这边做转换,假如在主线层做这个操作对性能会有一定的影响。
Color misaligned images
被缩放的图片会被标记为黄色,像素不对齐则会标注为紫色。
Color offscreen-rendered yellow
标示哪些layer需要做离屏渲染(offscreen-render)。

当你碰到性能问题的时候,你可以思考一下:
是否受到CPU或者GPU的限制?
是否有不必要的CPU渲染?
是否有太多的离屏渲染操作?
是否有太多的图层混合操作?
是否有奇怪的图片格式或者尺寸?
是否涉及到昂贵的view或者效果?
view的层次结构是否合理?
那么哪些是你最该开始考虑的方向呢?通常发生图形性能问题的时候,比如列表滑动不顺畅、动画卡顿等,大部分都是由于Offscreen Rendering(离屏渲染)或者blending导致的,因为这在动画的每一帧都会涉及到。

CPU的offscreen-render

使用CPU来完成渲染操纵,通常在你使用:
drawRect (如果没有自定义绘制的任务就不要在子类中写一个空的drawRect方法,因为只要实现了该方法,就会为视图分配一个寄宿图,这个寄宿图的像素尺寸等于视图大小乘以 contentsScale的值,造成资源浪费)

使用Core Graphics
上面的两种情况使用的就是CPU离屏渲染,首先分配一块内存,然后进行渲染操作生成一份bitmap位图,整个渲染过程会在你的应用中同步的进行,接着再将位图打包发送到iOS里一个单独的进程--render server,理想情况下,render server将内容交给GPU直接显示到屏幕上。

GPU的offscreen-render

使用GPU在当前屏幕缓冲区以外开辟一个新的缓冲区进行绘制,通常发生的情况有:
设置cornerRadius, masks, shadows,edge antialiasing等
设置layer.shouldRasterize = YES

Blending

假如最上层的view是不透明的,那直接使用这个view的对应颜色之就可以,但如果view是透明的,在计算像素的颜色值时就需要计算它下面图层,透明的视图越多,计算量就越大,因此也会对图形的性能产生一定的影响,所以可以的话也尽量减少透明图层的数目。

shadowPath

设置label的阴影效果可以通过:

cell.sign.layer.shadowOffset = CGSizeMake(0, 2);
cell.sign.layer.shadowOpacity = 0.5;
cell.sign.layer.shadowColor = [UIColor blackColor].CGColor;

但是你可以发现这会导致离屏渲染,一个简单的不需要离屏渲染的方法就是制定阴影的路径,也就是设置layer的shadowPath属性,通过instruments发现阴影的地方没有黄色了,帧率也提高到了40FPS:

cell.sign.layer.shadowPath = [UIBezierPath bezierPathWithRect:cell.sign.bounds].CGPath;

rasterize

对于圆角这种类似导致的性能问题,最简单的就是在列表中不要使用圆角,假如要使用圆角的话,一种最快提升性能的方式就是设置layer的shouldRasterize为YES:

cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;

虽然被Rasterize的图层也会引起离屏渲染

layer设置shouldRasterize=YES之后,会把被光栅化的图层保存成位图并缓存起来,其中圆角或者阴影之类的效果也是直接保存到位图当中,

当需要渲染到屏幕上的时候只需要到缓存中去取对应的位图进行显示就行了,加快了整个渲染过程。

可以通过勾选instruments core animation中的Color Hits Green and Misses Red选项来查看图层是否被缓存了,如果图层显示为绿色则表示已经被缓存起来了,也就是这个缓冲区的内容被复用了,不用在去重新创建缓冲区,反之则是用红色标示。

光栅化对于那些有很多子view嵌套在一起、view的层级复杂或者有很复杂特效效果的图层有很明显的提升,因为这些内容都被缓存到位图当中了。
但是使用光栅化需要注意一些内容:
1、适用于内容基本不变的图层
2、假如图层的内容经常变化,比如cell里面有涉及到动画之类的,那么缓存的内容就无效了,GPU需要重新创建缓存区,导致离屏渲染,这又涉及到OpenGL的上下文环境切换,反而降低性能。
3、不要过度使用
4、缓存区的大小被设置为屏幕大小的2.5倍,假如过分使用同样会导致大量的离屏渲染。
5、如果缓存的内容超过100ms没有被使用则会被回收。

对于圆角可以使用一张中间圆形透明的图覆盖在上面,虽然这会引入blending操作,但是大部分情况下性能会比离屏渲染好。

让你的view层次结构平坦一些,因为OpenGL在渲染layer的时候,在碰到有子层级layer的时候可能需要停下来把两者合成到一个buffer里再接着渲染。

延迟加载图片

有时候在边滚动边设置图片的时候可能会有一定的影响,因此可以在滚动的时候imageview不执行setimage的操作,滚动停止的时候才加载图片,由于滚动的时候NSRunloop是处于UITrackingRunLoopMode模式下,可以采用如下的方式,将设置图片放到NSDefaultRunLoopMode模式下才进行:

UIImage *downloadedImage = ...;
[self.avatarImageView performSelector:@selector(setImage:)
withObject:downloadedImage
afterDelay:0
inModes:@[NSDefaultRunLoopMode]];

图片加载的极限优化方式:FastImageCache

你可能感兴趣的:(iOS app性能相关)