iOS界面渲染流程分析

栏目: IOS · 发布时间: 5年前

内容简介:前言本文阅读建议1.一定要辩证的看待本文.

前言

本文阅读建议

1.一定要辩证的看待本文.

2.本文所表达观点并不是最终观点,还会更新,因为本人还在学习过程中,有什么遗漏或错误还望各位指出.

3.觉得哪里不妥请在评论留下建议~

4.觉得还行的话就点个小心心鼓励下我吧~

在最近的面试中,我发现一道面试题,其考点是: 围绕iOS App中一个视图从添加到完全渲染,在这个过程中,iOS系统都做了什么?

在进行了大量的文章查阅以及学习以后,将所有较为可靠的资料总结一下供大家参考。

面试题

本文可为以下面试题提供参考:

app从点击屏幕(硬件)到完全渲染,中间发生了什么?越详细越好 要求讲到进程间通信?出处

一个UIImageView添加到视图上以后,内部是如何渲染到手机上的,请简述其流程?

在一个表内有很多cell,每个cell上有很多个视图,如何解决卡顿问题?

简答

iOS渲染视图的核心是Core Animation

其渲染层次依次为:图层树->呈现树->渲染树

CPU阶段

  1. 布局(Frame)

  2. 显示(Core Graphics)

  3. 准备(QuartzCore/Core Animation)

  4. 通过IPC提交(打包好的图层树以及动画属性)

OpenGL ES阶段

  1. 生成(Generate)

  2. 绑定(Bind)

  3. 缓存数据(Buffer Data)

  4. 启用(Enable)

  5. 设置指针(Set Pointers)

  6. 绘图(Draw)

  7. 清除(Delete)

GPU阶段

  1. 接收提交的纹理(Texture)和顶点描述(三角形)

  2. 应用变换(transform)

  3. 合并渲染(离屏渲染等)

其iOS平台渲染核心原理的重点主要围绕前后帧缓存、Vsync信号、CADisplayLink

文字简答:

  1. 首先一个视图由CPU进行Frame布局,准备视图和图层的层级关系,查询是否有重写drawRect:或drawLayer:inContext:方法,注意:如果有重写的话,这里的渲染是会占用CPU进行处理的。

  2. CPU会将处理视图和图层的层级关系打包,通过IPC(内部处理通信)通道提交给渲染服务,渲染服务由OpenGL ES和GPU组成。

  3. 渲染服务首先将图层数据交给OpenGL ES进行纹理生成和着色。生成前后帧缓存,再根据显示硬件的刷新频率,一般以设备的Vsync信号和CADisplayLink为标准,进行前后帧缓存的切换。

  4. 最后,将最终要显示在画面上的后帧缓存交给GPU,进行采集图片和形状,运行变换,应用文理和混合。最终显示在屏幕上。

以上仅仅是对该题简单回答,其中的原理以及瓶颈和优化,后面会详细介绍。

知识点

  1. 重新认识Core Animation

  2. CPU渲染职能

  3. OpenGL ES渲染职能

  4. GPU渲染职能

  5. IPC内部通信(进程间通信)

  6. 前后帧缓存&Vsync信号

  7. 视图渲染优化&卡顿优化

  8. Metal渲染引擎

重新认识Core Animation

苹果官方文档-Core Animation

Core Animation并仅仅是字面意思的核心动画,而是整个显示核心都是围绕QuartzCore框架中的Core Animation

iOS界面渲染流程分析

Core Animation是依赖于OpenGL ES做GPU渲染,CoreGraphics做CPU渲染,但在本文中,以及官方文档都是将OpenGL与GPU分开说明。

iOS界面渲染流程分析

Core Animation 在 RunLoop 中注册了一个 Observer,监听了 BeforeWaiting 和 Exit 事件。这个 Observer 的优先级是 2000000,低于常见的其他 Observer。当一个触摸事件到来时,RunLoop 被唤醒,App 中的代码会执行一些操作,比如创建和调整视图层级、设置 UIView 的 frame、修改 CALayer 的透明度、为视图添加一个动画;这些操作最终都会被 CALayer 捕获,并通过 CATransaction 提交到一个中间状态去(CATransaction 的文档略有提到这些内容,但并不完整)。当上面所有操作结束后,RunLoop 即将进入休眠(或者退出)时,关注该事件的 Observer 都会得到通知。这时 CA 注册的那个 Observer 就会在回调中,把所有的中间状态合并提交到 GPU 去显示;如果此处有动画,CA 会通过 DisplayLink 等机制多次触发相关流程。

CPU渲染职能

在这里推荐大家去阅读 落影loyinglin 的文章 iOS开发-视图渲染与性能优化

显示逻辑

  • CoreAnimation提交会话,包括自己和子树(view hierarchy)的layout状态等;

  • RenderServer解析提交的子树状态,生成绘制指令

  • GPU执行绘制指令

  • 显示渲染后的数据

iOS界面渲染流程分析

提交流程

布局(Layout)

  • 调用layoutSubviews方法

  • 调用addSubview:方法

显示(Display)

  • 通过drawRect绘制视图;

  • 绘制string(字符串);

准备提交(Prepare)

  • 解码图片;

  • 图片格式转换;

提交(Commit)

  • 打包layers并发送到渲染server;

  • 递归提交子树的layers;

  • 如果子树太复杂,会消耗很大,对性能造成影响;

CPU渲染职能主要体现在以下5个方面:

布局计算

如果你的视图层级过于复杂,当视图呈现或者修改的时候,计算图层帧率就会消耗一部分时间。特别是使用iOS6的自动布局机制尤为明显,它应该是比老版的自动调整逻辑加强了CPU的工作。

视图懒加载

iOS只会当视图控制器的视图显示到屏幕上时才会加载它。这对内存使用和程序启动时间很有好处,但是当呈现到屏幕上之前,按下按钮导致的许多工作都会不能被及时响应。比如控制器从数据库中获取数据,或者视图 从一个nib文件中加载,或者涉及IO的图片显示,都会比CPU正常操作慢得多。

Core Graphics绘制

如果对视图实现了drawRect:或drawLayer:inContext:方法,或者 CALayerDelegate 的 方法,那么在绘制任何东 西之前都会产生一个巨大的性能开销。为了支持对图层内容的任意绘制,Core Animation必须创建一个内存中等大小的寄宿图片。然后一旦绘制结束之后, 必须把图片数据通过IPC传到渲染服务器。在此基础上,Core Graphics绘制就会变得十分缓慢,所以在一个对性能十分挑剔的场景下这样做十分不好。

解压图片

PNG或者JPEG压缩之后的图片文件会比同质量的位图小得多。但是在图片绘制到屏幕上之前,必须把它扩展成完整的未解压的尺寸(通常等同于图片宽 x 长 x 4个字节)。为了节省内存,iOS通常直到真正绘制的时候才去解码图片。根据你加载图片的方式,第一次对 图层内容赋值的时候(直接或者间接使用 UIImageView )或者把它绘制到 Core Graphics中,都需要对它解压,这样的话,对于一个较大的图片,都会占用一定的时间。

图层打包

当图层被成功打包,发送到渲染服务器之后,CPU仍然要做如下工作:为了显示 屏幕上的图层,Core Animation必须对渲染树种的每个可见图层通过OpenGL循环 转换成纹理三角板。由于GPU并不知晓Core Animation图层的任何结构,所以必须 要由CPU做这些事情。这里CPU涉及的工作和图层个数成正比,所以如果在你的层 级关系中有太多的图层,就会导致CPU没一帧的渲染,即使这些事情不是你的应用 程序可控的。

OpenGL ES渲染职能

这里推荐大家去看《OpenGL ES应用开发实践指南:iOS卷》,因为篇幅过长,就不赘述OpenGL的原理。

iOS界面渲染流程分析

简单来说,OpenGL ES是对图层进行取色,采样,生成纹理,绑定数据,生成前后帧缓存。

纹理的概念:纹理是一个用来保存图像的颜色元


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Principles of Object-Oriented JavaScript

Principles of Object-Oriented JavaScript

Nicholas C. Zakas / No Starch Press / 2014-2 / USD 24.95

If you've used a more traditional object-oriented language, such as C++ or Java, JavaScript probably doesn't seem object-oriented at all. It has no concept of classes, and you don't even need to defin......一起来看看 《Principles of Object-Oriented JavaScript》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换