百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

iOS 视图---动画渲染机制探究(关闭苹果动画渲染)

bigegpt 2025-03-20 12:36 5 浏览

腾讯Bugly特约作者:陈向文

终端的开发,首当其冲的就是视图、动画的渲染,切换等等。用户使用 App 时最直接的体验就是这个界面好不好看,动画炫不炫,滑动流不流畅。UI就是 App 的门面,它的体验伴随着用户使用 App 的整个过程。如果UI失败,用户是不会有打开第二次的欲望的。

iOS 为开发者提供了丰富的 Framework(UIKit,Core Animation,Core Graphic,OpenGL 等等)来满足开发从上层到底层各种各样的需求。不得不说苹果很牛逼,很多接口你根本不需要理解背后的原理就能上手使用并且满足你大部分的需求,但是,如果遇到性能问题就容易抓瞎。易用性跟优化就是个矛盾体,就像 ARC 一样,当你没有遇到内存问题的时候用得很爽,一旦遇到了,就要要求你比在用 MRC 的时候更加了解 iOS 的内存机制。UI 亦是如此。况且,作为鹅厂的员工当然不能仅限于知道怎么用。我们要知其然还要知其所以然。好了,废话不说,我们进入主题:看看 iOS 是如何渲染视图和动画的,以及在我们遇到渲染的性能问题时怎么做优化。

(注意:以下内容是笔者的一些踩坑经验和总结, 欢迎探讨!)

先来看看官方对 Core Animation 的一段说明:

可以看出iOS渲染视图的核心是 Core Animation。从底层到上层依此是 GPU->(OpenGL、Core Graphic) -> Core Animation -> UIKit。

在 iOS上,动画和视图的渲染其实是在另外一个进程做的(下面我们叫这个进程 render server),在 iOS 5 以前这个进程叫 SpringBoard,在 iOS 6 之后叫 BackBoard。

下面这幅图是使用项目录制视频的时候(大量视图渲染),整个系统的进程情况:

可以很清楚地看到 BackBoard 这个进程的情况。

iOS 上视图或者动画渲染的各个阶段:

在 APP 内部的有4个阶段:

  • 布局:在这个阶段,程序设置 View / Layer 的层级信息,设置 layer 的属性,如 frame,background color 等等。

  • 创建 backing image:在这个阶段程序会创建 layer 的 backing image,无论是通过 setContents 将一个 image 传給 layer,还是通过 [drawRect:] 或 [drawLayer: inContext:] 来画出来的。所以 [drawRect:] 等函数是在这个阶段被调用的。

  • 准备:在这个阶段,Core Animation 框架准备要渲染的 layer 的各种属性数据,以及要做的动画的参数,准备传递給 render server。同时在这个阶段也会解压要渲染的 image。(除了用 imageNamed:方法从 bundle 加载的 image 会立刻解压之外,其他的比如直接从硬盘读入,或者从网络上下载的 image 不会立刻解压,只有在真正要渲染的时候才会解压)。

  • 提交:在这个阶段,Core Animation 打包 layer 的信息以及需要做的动画的参数,通过 IPC(inter-Process Communication)传递給 render server。

在 APP 外部的2个阶段:

当这些数据到达 render server 后,会被反序列化成 render tree。然后 render server 会做下面的两件事:

  • 根据 layer 的各种属性(如果是动画的,会计算动画 layer 的属性的中间值),用 OpenGL 准备渲染。

  • 渲染这些可视的 layer 到屏幕。

如果做动画的话,最后的两个步骤会一直重复知道动画结束。

我们都知道 iOS 设备的屏幕刷新频率是 60HZ。如果上面的这些步骤在一个刷新周期之内无法做完(1/60s),就会造成掉帧。

我们看看有哪些操作可能会过度消耗 CPU 或者 GPU,从而造成掉帧。

如果视图的层级结构太复杂的话,当某些视图被渲染或者 frame 被修改的话,CPU 会花比较多得时间去重新计算 frame。尤其如果用 autolayout 的话,会更消耗 CPU。同时过多的几何结构会大大增多需要渲染的 OpenGL triangles 以及栅格化的操作(将 OpenGL 的 triangles 转化成像素)

  • 太多的 overdraw:overdraw是指一个像素点被多次地用颜色填充。这个主要是由于一些半透明的 layer 相互重叠造成的。GPU 的 fill-rate(用颜色填充像素的速率)是有限的。如果 overdraw 太多的话,势必会降低 GPU 的性能。

  • 视图的延后载入:iOS 只有在展示 viewcontroller 的 view 或者访问 viewcontroller 的 view,比如说 someviewcontroller.view 的时候才会加载view。如果在用户点击了某个 button,并且在 button 的响应函数里做了很多消耗 cpu 的工作,这个时候如果 present 某个 viewcontroller 的话,会容易卡顿,尤其是如果viewcontroller 要从 database 里获取数据,或者从 nib 文件初始化 view 或者加载图片会更卡。

  • 离屏的绘制:离屏的绘制有两种情况:1. 有些效果(如 rounded corners,layer masks,drop shadows 和 layer rasterization)不能直接的绘制到屏幕上,必须先绘制到一个 offscreen 的 image context 上,这种操作会引入额外的内存和 CPU 消耗。2. 实现了 drawRect 或者 drawLayer:inContext:,为了支持任意的绘制,core graphic 会创建一个大小跟要画的 view 一样的 backing image。并且当画完的以后要传输到 render server 上渲染。所以没事不要重载 drawRect 等函数却什么都不做。

  • 图片解压:用 imageNamed:从 bundle 里加载会立马解压。一般的情况是在赋值给 UIImageView 的 image 或者 layer 的 contents 或者画到一个 core graphic context 里才会解压。

渲染性能优化的注意点:

隐藏的绘制:catextlayer 和 uilabel 都是将 text 画入 backing image 的。如果改了一个包含 text 的 view 的 frame 的话,text 会被重新绘制。

Rasterize:当使用 layer 的 shouldRasterize 的时候(记得设置适当的 laye r的 rasterizationScale),layer 会被强制绘制到一个 offscreen image 上,并且会被缓存起来。这种方法可以用来缓存绘制耗时(比如有比较绚的效果)但是不经常改的 layer,如果 layer 经常变,就不适合用。

离屏绘制: 使用 Rounded corner, layer masks, drop shadows 的效果可以使用 stretchable images。比如实现 rounded corner,可以将一个圆形的图片赋值于 layer 的 content 的属性。并且设置好 contentsCenter 和 contentScale 属性。

Blending and Overdraw :如果一个 layer 被另一个 layer 完全遮盖,GPU 会做优化不渲染被遮盖的 layer,但是计算一个 layer 是否被另一个 layer 完全遮盖是很耗 cpu 的。将几个半透明的 layer 的 color 融合在一起也是很消耗的。

我们要做的:

  1. 设置 view 的 backgroundColor 为一个固定的,不透明的 color。

  2. 如果一个 view 是不透明的,设置 opaque 属性为 YES。(直接告诉程序这个是不透明的,而不是让程序去计算)

这样会减少 blending 和 overdraw。

如果使用 image 的话,尽量避免设置 image 的 alpha 为透明的,如果一些效果需要几个图片融合而成,就让设计用一张图画好,不要让程序在运行的时候去动态的融合。

好了,介绍完这些渲染优化需要注意的点,让我们用 instrument 的 Core Animation 和 GPU Driver 来看看一些具体的例子。

Core Animation:

Color Blended Layers:看半透明 layer 的遮盖情况。从绿到红,越红遮盖越大。

这下这两幅图是测量项目详情页的半透明的 layer 的情况。可以看到详情页这里半透明的 layer 还是比较多的,但不是说半透明的 layer 很多,范围很大就要优化,要参看 GPU Driver 的测量情况看,下面会介绍

Color Hits Green and Misses Red:当使用shouldRasterize的时候,layer drawing 会被缓存起来,如果 rasterized 的 layer 需要被重新绘制,会标示红。

下面是项目消息列表的 cell 设置 shouldRasterize=YES 的情况,每个 cell 的 layer 的 backing image 会被缓存起来,如果往下滚动 tableview 的话,由于 cell 会被复用,这样 layer 就会被重绘,会被标红。

Color Offscreen-Rendered Yellow:如果要做 offscreen drawing 的话,会标成黄色。

下面是项目的首页,由于圆形头像的实现方式是设置 roundedCorner 的属性来实现,所以会触发 offscreen drawing。

Core Animation Template 只是能让开发者直观地看到哪些地方有可能需要优化,但是到底要不要优化,还是要看 GPU Driver 的表现。

GPU Driver

Renderer Utilization ——如果这个值大于50%的话,表示 GPU 的性能受到 fill-rate 的限制,可能有太多的 Offscreen rendering,overdraw,blending。

Tiler Utilization ——如果这个值大于50%,表示可能有太多的 layers。

我们以上面的那个项目的详情页为例,看看 GPU driver 的测量:

可以看到这 Renderer Utilization 是20%左右,Tiler Utilization 时15%,可以不用优化,(当然这里我们先不考虑 CPU 的使用情况,只是单单针对上面 Core Animation Template 的一些测量说不用做针对性的优化)

这里想说的一点是,以上所说的点只是在我们遇到渲染性能问题的时候給我们提供优化的方向跟思路。优化往往代表着更复杂,难懂的代码,在没有遇到渲染性能问题的时候不要过度优化。

希望对大家有帮助!

相关推荐

得物可观测平台架构升级:基于GreptimeDB的全新监控体系实践

一、摘要在前端可观测分析场景中,需要实时观测并处理多地、多环境的运行情况,以保障Web应用和移动端的可用性与性能。传统方案往往依赖代理Agent→消息队列→流计算引擎→OLAP存储...

warm-flow新春版:网关直连和流程图重构

本期主要解决了网关直连和流程图重构,可以自此之后可支持各种复杂的网关混合、多网关直连使用。-新增Ruoyi-Vue-Plus优秀开源集成案例更新日志[feat]导入、导出和保存等新增json格式支持...

扣子空间体验报告

在数字化时代,智能工具的应用正不断拓展到我们工作和生活的各个角落。从任务规划到项目执行,再到任务管理,作者深入探讨了这款工具在不同场景下的表现和潜力。通过具体的应用实例,文章展示了扣子空间如何帮助用户...

spider-flow:开源的可视化方式定义爬虫方案

spider-flow简介spider-flow是一个爬虫平台,以可视化推拽方式定义爬取流程,无需代码即可实现一个爬虫服务。spider-flow特性支持css选择器、正则提取支持JSON/XML格式...

solon-flow 你好世界!

solon-flow是一个基础级的流处理引擎(可用于业务规则、决策处理、计算编排、流程审批等......)。提供有“开放式”驱动定制支持,像jdbc有mysql或pgsql等驱动,可...

新一代开源爬虫平台:SpiderFlow

SpiderFlow:新一代爬虫平台,以图形化方式定义爬虫流程,不写代码即可完成爬虫。-精选真开源,释放新价值。概览Spider-Flow是一个开源的、面向所有用户的Web端爬虫构建平台,它使用Ja...

通过 SQL 训练机器学习模型的引擎

关注薪资待遇的同学应该知道,机器学习相关的岗位工资普遍偏高啊。同时随着各种通用机器学习框架的出现,机器学习的门槛也在逐渐降低,训练一个简单的机器学习模型变得不那么难。但是不得不承认对于一些数据相关的工...

鼠须管输入法rime for Mac

鼠须管输入法forMac是一款十分新颖的跨平台输入法软件,全名是中州韵输入法引擎,鼠须管输入法mac版不仅仅是一个输入法,而是一个输入法算法框架。Rime的基础架构十分精良,一套算法支持了拼音、...

Go语言 1.20 版本正式发布:新版详细介绍

Go1.20简介最新的Go版本1.20在Go1.19发布六个月后发布。它的大部分更改都在工具链、运行时和库的实现中。一如既往,该版本保持了Go1的兼容性承诺。我们期望几乎所...

iOS 10平台SpriteKit新特性之Tile Maps(上)

简介苹果公司在WWDC2016大会上向人们展示了一大批新的好东西。其中之一就是SpriteKitTileEditor。这款工具易于上手,而且看起来速度特别快。在本教程中,你将了解关于TileE...

程序员简历例句—范例Java、Python、C++模板

个人简介通用简介:有良好的代码风格,通过添加注释提高代码可读性,注重代码质量,研读过XXX,XXX等多个开源项目源码从而学习增强代码的健壮性与扩展性。具备良好的代码编程习惯及文档编写能力,参与多个高...

Telerik UI for iOS Q3 2015正式发布

近日,TelerikUIforiOS正式发布了Q32015。新版本新增对XCode7、Swift2.0和iOS9的支持,同时还新增了对数轴、不连续的日期时间轴等;改进TKDataPoin...

ios使用ijkplayer+nginx进行视频直播

上两节,我们讲到使用nginx和ngixn的rtmp模块搭建直播的服务器,接着我们讲解了在Android使用ijkplayer来作为我们的视频直播播放器,整个过程中,需要注意的就是ijlplayer编...

IOS技术分享|iOS快速生成开发文档(一)

前言对于开发人员而言,文档的作用不言而喻。文档不仅可以提高软件开发效率,还能便于以后的软件开发、使用和维护。本文主要讲述Objective-C快速生成开发文档工具appledoc。简介apple...

macOS下配置VS Code C++开发环境

本文介绍在苹果macOS操作系统下,配置VisualStudioCode的C/C++开发环境的过程,本环境使用Clang/LLVM编译器和调试器。一、前置条件本文默认前置条件是,您的开发设备已...