内容简介:前言本文阅读建议1.一定要辩证的看待本文.
前言
本文阅读建议
1.一定要辩证的看待本文.
2.本文所表达观点并不是最终观点,还会更新,因为本人还在学习过程中,有什么遗漏或错误还望各位指出.
3.觉得哪里不妥请在评论留下建议~
4.觉得还行的话就点个小心心鼓励下我吧~
在最近的面试中,我发现一道面试题,其考点是: 围绕iOS App中一个视图从添加到完全渲染,在这个过程中,iOS系统都做了什么?
在进行了大量的文章查阅以及学习以后,将所有较为可靠的资料总结一下供大家参考。
面试题
本文可为以下面试题提供参考:
app从点击屏幕(硬件)到完全渲染,中间发生了什么?越详细越好 要求讲到进程间通信?出处
一个UIImageView添加到视图上以后,内部是如何渲染到手机上的,请简述其流程?
在一个表内有很多cell,每个cell上有很多个视图,如何解决卡顿问题?
简答
iOS渲染视图的核心是Core Animation
其渲染层次依次为:图层树->呈现树->渲染树
CPU阶段
-
布局(Frame)
-
显示(Core Graphics)
-
准备(QuartzCore/Core Animation)
-
通过IPC提交(打包好的图层树以及动画属性)
OpenGL ES阶段
-
生成(Generate)
-
绑定(Bind)
-
缓存数据(Buffer Data)
-
启用(Enable)
-
设置指针(Set Pointers)
-
绘图(Draw)
-
清除(Delete)
GPU阶段
-
接收提交的纹理(Texture)和顶点描述(三角形)
-
应用变换(transform)
-
合并渲染(离屏渲染等)
其iOS平台渲染核心原理的重点主要围绕前后帧缓存、Vsync信号、CADisplayLink
文字简答:
-
首先一个视图由CPU进行Frame布局,准备视图和图层的层级关系,查询是否有重写drawRect:或drawLayer:inContext:方法,注意:如果有重写的话,这里的渲染是会占用CPU进行处理的。
-
CPU会将处理视图和图层的层级关系打包,通过IPC(内部处理通信)通道提交给渲染服务,渲染服务由OpenGL ES和GPU组成。
-
渲染服务首先将图层数据交给OpenGL ES进行纹理生成和着色。生成前后帧缓存,再根据显示硬件的刷新频率,一般以设备的Vsync信号和CADisplayLink为标准,进行前后帧缓存的切换。
-
最后,将最终要显示在画面上的后帧缓存交给GPU,进行采集图片和形状,运行变换,应用文理和混合。最终显示在屏幕上。
以上仅仅是对该题简单回答,其中的原理以及瓶颈和优化,后面会详细介绍。
知识点
-
重新认识Core Animation
-
CPU渲染职能
-
OpenGL ES渲染职能
-
GPU渲染职能
-
IPC内部通信(进程间通信)
-
前后帧缓存&Vsync信号
-
视图渲染优化&卡顿优化
-
Metal渲染引擎
重新认识Core Animation
Core Animation并仅仅是字面意思的核心动画,而是整个显示核心都是围绕QuartzCore框架中的Core Animation
Core Animation是依赖于OpenGL ES做GPU渲染,CoreGraphics做CPU渲染,但在本文中,以及官方文档都是将OpenGL与GPU分开说明。
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执行绘制指令
-
显示渲染后的数据
提交流程
布局(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的原理。
简单来说,OpenGL ES是对图层进行取色,采样,生成纹理,绑定数据,生成前后帧缓存。
纹理的概念:纹理是一个用来保存图像的颜色元
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Google 推出 Node 应用 Web 渲染界面 Carlo
- iOS 性能优化思路:界面离屏渲染、图层混色
- mlog-club 1.0.5 发布,使用 nuxt.js 渲染界面
- 美团开源Graver框架:用“雕刻”诠释iOS端UI界面的高效渲染
- CentOS 图形界面和字符界面切换
- GUI 界面如何设计?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。