美文网首页iOS Swift && Objective-C
如何做一个流畅的UI?--组内分享记录

如何做一个流畅的UI?--组内分享记录

作者: 一铭_ | 来源:发表于2017-03-26 16:37 被阅读160次

    前提
    最近做了一次组内分享,这个 idea 来自去沪江的分享会听到的,学到了一些,也分享给组内的小伙伴.

    什么是卡顿?

    这件事要从RunLoop开始,RunLoop是一个60FPS[注1]的回调,也就是说每16.7ms绘制一次屏幕,也就是我们需要在这个时间内完成缓冲区创建,缓冲区内容的绘制这些是CPU的工作;然后把缓冲区交给GPU渲染,这里包括了多个View的拼接(Compositing),纹理的渲染(Texture)等等,最后Display到屏幕上。但是如果你在16.7ms内做的事情太多,导致CPU,GPU无法在指定时间内完成指定的工作,那么就会出现卡顿现象,也就是丢帧。

    用户能感受到的卡顿:

    1.页面的 FPS 降低,滑动时有困顿;
    2.页面卡死,无法响应;
    3.主线程的 Runloop 执行了很久;

    可能是什么原因导致了卡顿:

    1.死锁:主线程拿到锁 A, 需要锁 B;子线程拿到锁 B,需要锁 A,相互等待导致死锁;
    2.抢锁:主线程需要读取 DB,子线程在插入数据.
    3.主线程大量 IO.
    4.主线程大量计算.
    5.大量的UI、复杂的UI绘制.

    屏幕的成像原理

    幻灯片06.jpg

    iOS的显示系统是由 Vsync 脉冲信号驱动的, Vsync 脉冲信号由硬件时钟生成,大约每秒钟发出60次, iPhone 采用的双缓冲,安卓在4.1之后是三缓冲.[注2]
    通常来说,计算机系统中的 CPU,GPU, 显示器的协同工作是:
    1.CPU 计算好显示内容提交到 GPU;
    2.GPU 渲染完成后将渲染结果放入 Back Buffer(第一缓冲区);
    3.然后等待显示器发的垂直同步信号(VSync),Frame Buffer(第二缓冲区)copy 第一缓冲区的显示内容
    4.显示屏经过数模转换显示出来.
    所以要避免卡顿就要在16.7ms 内完成第一缓冲区的创建,所以我们所能做的优化绝大部分要在CPU,GPU这两部分.

    如何使页面流畅

    从CPU入手:

    先看看CPU要做的事情:
    1.对象创建;
    2.布局计算;
    3.复杂算法;
    4.AutoLayout;
    5.文本图片的绘制;
    这仅仅是列出一小部分CPU的工作,可以尝试如何从以上几条来优化:
    1.对象创建:对象的创建会分配内存、调整属性、文件的 IO等操作,这些都比较占 CPU的资源,如果一个
    对象的创建会分配内存、调整属性、甚至还有读取文件等操作

    从GPU入手:

    GPU的职责:根据CPU提供的内容进行渲染,输出到屏幕上.
    在 Core Animation的组成部分中, OpenGL ES 是直接调用 GPU 进行渲染的.它有两种渲染方式:

    • On-Screen Rendering
    • Off-Screen Rendering:是指GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作.
    为什么离屏渲染会带来性能消耗?

    1.创建新的缓冲区
    2.多次上下文切换

    离屏渲染的触发方式

    1.光栅化(shouldRasterize)[注3]
    2.遮罩(masks)
    3.阴影(shadows)
    4.不透明(opacity)
    5.圆角

    更多可优化点:

    • 异步绘制
    • 算法优化
    • AsyncDisplayKit
    • ...

    参考文档

    Q&A

    注:

    注1.FPS是图像领域中的定义,是指画面每秒传输帧数,通俗来讲就是指动画或视频的画面数。FPS是测量用于保存、显示动态视频的信息数量。每秒钟帧数愈多,所显示的动作就会愈流畅

    注2.通常来说,计算机系统中 CPU、GPU、显示器是以上面这种方式协同工作的。CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示

    注3..当一个列表视图中出现大量圆角的 CALayer,并且快速滑动时,可以观察到 GPU 资源已经占满,而 CPU 资源消耗很少。这时界面仍然能正常滑动,但平均帧数会降到很低。为了避免这种情况,可以尝试开启 CALayer.shouldRasterize 属性,但这会把原本离屏渲染的操作转嫁到 CPU 上去。

    相关文章

      网友评论

        本文标题:如何做一个流畅的UI?--组内分享记录

        本文链接:https://www.haomeiwen.com/subject/ldjkottx.html