0
点赞
收藏
分享

微信扫一扫

iOS渲染过程

背景

应用运行的卡顿率是一个十分重要的指标,相比慢、发热、占用内存高来讲,卡顿是用户第一时间能感知的东西,三步两卡的应用基本逃不出被卸载的命运,要想优化卡顿就要搞清楚画面卡住不动的原因,这就需要对整个渲染过程有一定了解,本文会从图层说起,来聊聊整个渲染过程以及优化点,在写这篇文章之前笔者努力在想,对于完全没有做过图形处理相关工作的道友来说,理解这个过程是有一些难度的,那么要怎么写才可以脉络清晰又浅显易懂呢,想来想去还是从日常开发中的界面UI开始分析吧,毕竟可直接感知

从一个简单的界面开始

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = UIColor.blueColor;
    // 蒙板视图
    UIView *maskView = [[UIView alloc] initWithFrame:self.view.bounds];
    maskView.backgroundColor = [UIColor redColor];
    maskView.alpha = 0.3;
    [self.view addSubview:maskView];
    // 初始化屏幕大小的矩形路径
    UIBezierPath *bpath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height) cornerRadius:8.0];
    // 中间添加一个圆形的路径
    [bpath appendPath:[UIBezierPath bezierPathWithArcCenter:maskView.center radius:100 startAngle:0 endAngle:2*M_PI clockwise:NO]];
    //创建一个layer设置其CGPath为我们创建的路径并且赋值给蒙板视图的layer
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = bpath.CGPath;
    maskView.layer.mask = shapeLayer;
}

效果如下:我们设置self.view的背景色为蓝色,然后添加了一层中间镂空的红色透明度0.3的蒙板,经过叠加、裁剪、混合(后面会详述)就是图中的效果

数一数得到图中的效果,我们一共用了几个元素

  • 一个蓝色背景UIView
  • 一个蒙板视图UIView
  • 一个用贝塞尔曲线修改过的CAShapeLayer

我们自己创建的元素有三个,背景视图上面添加蒙板视图,蒙板视图的图层的蒙板层mask设置为自定义的镂空CAShapeLayer层,可见开发中既有视图又有图层,会不会觉得有些冗余呢

视图和图层为何拆分开来又聚合在一起呢

这是自图形界面发明出来就广泛应用的设计,拆开之后,layer负责界面显示,view负责事件分发,聚合一起是因为操作起来更方便,不能说开发者设置完事件层次之后,再设置一遍图层层次吧

因此当我们研究渲染过程的时候,只需要关注CALayer即可

渲染数据流

纵观我们的app界面,图层上面加图层,图层又有子图层,整个结构是以CALayer或其子类对象为节点连接而成的树型结构,我们通常称之为图层树,苹果称其为模型树,layer默认是个矩形,我们可以通过path属性修改其形状,可以修改为圆形、三角形等任何规则不规则的形状,那么从图层树到屏幕上显示的界面都需要哪些步骤呢,如果你去查资料你可能会翻到图层树->呈现树->渲染树,那么他们都是什么东西呢,数据是如何流转的,CPU、GPU和渲染引擎都扮演了怎样的角色呢,我们来拆解下渲染数据流的处理过程

以上过程图层树已生成,就是以CALayer对象为节点的树型结构

以上过程呈现树已生成,图层树、呈现树构建过程都是由CPU负责计算

以上过程都由渲染引擎处理,除了生成纹理是CPU负责,其他都全权由GPU负责,以上就是界面渲染的全部过程,那我们自定义的画布呢,比如常见的播放器业务、地图业务都是怎么最终显示到屏幕的呢

自定义画布

这篇文章有详述其组织渲染过程,但是渲染到帧缓存之后,显示到屏幕过程是怎样的呢
iOS中是不支持直接渲染到屏幕的,我们的自定义画布,需要配合Core Animation来完成最终的显示,诸如播放器、地图等业务得到的渲染缓冲renderBuffer,需要通过layer关联到Core Animation层,待到生成渲染树的时候替换原来的内容,此过程只是一个指针替换,即将渲染树对应层的指针指向renderBuffer,然后由渲染引擎通过GPU最终将其呈现到屏幕

图层截图黑屏问题

播放器、地图类业务图层截图的时候会黑屏,原因是图层截图截取的是呈现树,此时自定义画布得到的renderBuffer还没有替换layer原来的内容,解决这个问题需要在截图的时候,将renderBuffer的内容在layer的上下文上单独绘制

当我们说界面卡了我们在说什么

页面卡顿,现象是当我们滑动列表或者点击一个按钮之后页面没有响应,本质原因是主线程卡了,因为整个UI界面的构建、计算、合成纹理过程都是在主线程进行的,主线程16.7毫秒之内没有执行完当前任务,该任务可能是:

  • 非UI业务逻辑耗时过多
  • 图层树构建组织过程耗时过多
  • 呈现树生成过程耗时过多

总之是渲染树没有更新导致看上去还是上一帧的画面,这就是卡顿

卡顿优化

优化卡顿无非就是减少上面几个步骤的耗时,使Runloop能在16.7毫秒之内执行完一次

总结

本文从一个简单的界面开始详细阐述了iOS渲染过程以及卡顿优化点,有些内容官方文档写的很清楚,甚至还有demo,大家在学习的时候首先应该关注的就是官方文档,下面给出两个官方参考链接:

CALayer
OpenGL ES Programming Guide

举报

相关推荐

0 条评论