iOS开发系列之性能优化(上)
本篇主要记录一下我对界面优化上的一些探索。关于时间优化的探索将会在中篇里进行介绍。下篇将主要介绍一些耗电优化、安装包瘦身的探索。
### 1、卡顿原理
要了解卡顿原理,需要对帧缓冲区、垂直同步、CPU 和 GPU 几个词进行一下了解,然后综合起来,就可以得到卡顿的答案。本篇我就按照自己的理解来进行描述,如有不当,欢迎指正。
#### 1.1、帧缓冲区
听起来很高大上,其实就是用来存放每一帧画面数据的一个“仓库”,一个仓库只存放一帧画面的数据,iOS 一直是双缓存,就是有两个仓库,存当前帧数据的叫“正式仓库”,存下一帧数据的叫“预备仓库”。
当正式仓库的数据被取走后,两者身份交换,原来的预备仓库转正为正式仓库,原来的正式仓库变成预备仓库。
#### 1.2、垂直同步 (VSync)
就是一个“信号”,通知 app 该开始准备往预备仓库里存放数据了,系统过一会就要来取,这个时间大概是16毫秒。
#### 1.3、CPU (中央处理器)
主要的工作有:正式对象的创建和销毁、对象属性的调整、布局计算、文本的计算和排版、图片的格式转换和解码、图像的绘制。我们可以理解为负责包裹内部的处理工作,简称“打包”。
#### 1.4、GPU (图形处理器)
主要的工作有:将 CPU 计算好的内容进行变换、合成、渲染等处理,然后将渲染结果提交到帧缓冲区。我们可以理解为,对 CPU 给过来的包裹进行分类、排列等操作后,存放到仓库里去,简称“入库”。
#### 1.5、卡顿原理
当收到系统发过来的 VSync “信号”后,CPU 就开始对这一帧画面的数据进行“打包”,然后交给 GPU 进行“入库”操作,存入到“预备仓库”中。
16毫秒后,预备仓库转正,系统开始读取仓库里的数据,如果这个时候,仓库中的数据还没有准备好,那么系统就会大发雷霆,放弃读取仓库中的数据。
那么这个时候,因为系统的宁缺毋滥,导致了显示器上显示的还是上一帧画面,就造成了卡顿的效果。
### 2、性能优化
作为软件开发工程师的我们,既不能延长16毫秒的处理时间,也不能改变系统的脾气,那我们能做的就是尽量在这个时间内完成数据的准备。要么“打包”快一点,要么“入库”快一点,也就是针对 CPU 和 GPU 的工作进行优化,这就是性能优化的工作了。
#### 2.1、CPU 工作之正式对象的创建和销毁
- UITableViewCell 和 UICollectionViewCell 的复用,可以减少 cell 的创建操作;
- 尽量使用轻量级的对象,可以减少对象的创建时间,比如在不需要事件处理的场景里,使用CALayer 比 UIView 会更加合适;
- 表情键盘使用 UICollectionViewCell 代替 UIButton,可以减少对象的创建操作;
- 对象不涉及UI操作,放到后台线程创建;
- 性能敏感的界面,storyborad的资源消耗>代码创建;
- 推迟对象创建的时间,对象放到多个任务中,比如懒加载;
#### 2.2、CPU 工作之对象属性的调整
- UIView 有一个 CALyer 的属性,UIView 负责事件的处理,CALyer 负责图层的绘制和显示。需要注意的是,CALyer本身是没有属性的,所以当改变 UIView 的显示相关的属性如 frame、bounds 和 transform 的时候,会消耗较多的资源,所以减少对这些属性的一些不必要修改,能减小 CPU 的压力;
#### 2.3、CPU 工作之布局计算
- UITableViewCell 高度提前计算并存储,要用的时候直接读取;
- frame 计算好,较少不必要的修改;
- Autolayout会比直接设置frame消耗更多的CPU资源;
#### 2.4、CPU 工作之文本的计算和排版
- 普通文本可以在子线程用 [NSAttributedString boundingRectWithSize:options:context:] 来计算文本宽高,用 -[NSAttributedString drawWithRect:options:context:] 来绘制文本;
- CoreText 对象占用内存较少,当显示大量文本时,可以用 CoreText 对文本异步绘制;
#### 2.5、CPU 工作之图片的格式转换和解码
- 在后台线程先把图片绘制到 CGBitmapContext 中,然后从 Bitmap 直接创建图片;
#### 2.6、CPU 工作之图像的绘制
- UITableViewCell 滑动减速的时候才加载图片,可以参考这个[demo](https://github.com/johnil/VVeboTableViewDemo);
- 加载图片时,imageNamed 方法默认加载图片成功后会内存中缓存图片,下次读取会很快;imageWithContentsOfFile 方法不会缓存图片,大图片可以使用该方法;
#### 2.7、GPU 工作之渲染
- 尽量不要让图片和视图的大小超过 GPU 纹理尺寸上限:4096×4096,不然图片还需要经过 CPU 的处理;
- 尽量减少视图数量和层次,并设置视图为不透明,UIView 的不透明属性 (opaque) 默认为 YES,一般设置背景颜色即可;CALayer 的不透明属性 (opaque) 默认为 NO,需要设置为 YES;
- CALayer 的 border、圆角、阴影、遮罩,通常会触发离屏渲染,尽量少用,圆角属性可以使用 CoreGraphics 绘制或使用圆角图片代替,关于离屏渲染的知识,具体可以参考这篇文章:[iOS 图形性能优化](http://www.cocoachina.com/cms/wap.php?action=article&id=25543);
- 图片的 size 最好刚好跟 UIImageView 的 size 保持一致,这涉及到像素对齐的知识,也可以在上面这篇文章中详细了解;
最后郑重声明,本篇里只是记录一下我的个人理解和代码实践,资料大量参考了这篇文章:[iOS 保持界面流畅的技巧](https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/),作者是写出了 YYKit 框架的大佬,想要深入学习的朋友请移步。
本篇的界面优化就记录到这里,后面会持续更新,欢迎指正。
iOS开发系列之性能优化(上)的更多相关文章
- Android开发系列之性能优化
一直想整理一篇关于Android性能优化的博客,正好今天借鉴一些书籍资料,总结一下自己对于这块的一些认识.相信大家都听说过16ms的原则,即每两个画面之间的绘制时间间隔不能超过16ms,否则人眼能够感 ...
- iOS开发那些事--性能优化–内存泄露问题的解决(转)
内存泄漏问题的解决 内存泄漏(Memory Leaks)是当一个对象或变量在使用完成后没有释放掉,这个对象一直占有着这块内存,直到应用停止.如果这种对象过多内存就会耗尽,其它的应用就无法运行.这个问题 ...
- iOS开发系列--Swift进阶
概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用S ...
- iOS开发系列--通知与消息机制
概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知机制就可以告诉用户此时发生的事情.iOS中通知机制又叫消息机制,其包括两类:一类是本地 ...
- iOS开发系列--让你的应用“动”起来
--iOS核心动画 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建 ...
- iOS开发系列--让你的应用“动”起来
--iOS核心动画 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建 ...
- IOS开发系列 --- 核心动画
原始地址:http://www.cnblogs.com/kenshincui/p/3972100.html 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥i ...
- iOS开发系列--让你的应用“动”起来【转载】
概览 原文链接:http://www.cnblogs.com/kenshincui/p/3972100.html 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥i ...
- iOS开发系列--通知与消息机制--转
来自:http://www.cocoachina.com/ios/20150318/11364.html 概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户 ...
随机推荐
- Leetcode 171 Excel Sheet Column Number 字符串处理
本质是把26进制转化为10进制 A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 class Solution ...
- 希尔伯特空间(Hilbert Space)
欧氏空间 → 线性空间 + 内积 ⇒ 内积空间(元素的长度,元素的夹角和正交) 内积空间 + 完备性 ⇒ 希尔伯特空间 0. 欧几里得空间 欧氏空间是一个特别的度量空间,它使得我们能够对其的拓扑性质, ...
- python3使用多代理访问网站
#------------------------------------------------------------------------------- # Name: module1 # P ...
- Halcon程序导出运行的方法
1 在Halcon中打开程序,如clip.hdev: 2 文件->导出 设置使用导出模板,使用UTF-8编码: 3 导出cs文件 4 新建Winform程序 5 在工具栏中点右键->选择项 ...
- CommandParameter binding Introduction:
Design Patterns SampleCode https://csharpdesignpatterns.codeplex.com/ DevExpress Support Center http ...
- 向WPF的Grid里面增加控件
在c#中,有时需要通过代码创建面板控件,但是对于面板的操作与之前的控件并不是很直观,因此记下方法,以供后来复习使用: 创建两行两列的表格: 第一种方法: Grid grid = new Grid(); ...
- IDEA 问题 & 解决
# 问题 Error: java: Compilation failed: internal java compiler error # 解决 http://blog.csdn.net/u011275 ...
- 深入理解Amazon Alexa Skill(一)
语音助手(Virtual Personal Assistants, VPA)是物联网智能家居中很火的一个领域,用户可以通过语言作为入口来控制家里各种各样的设备,而亚马逊的Alexa(echo,echo ...
- Qt实现长文件名(字符串)在QLabel中自适应缩短
一.应用场景简述 当在有限宽度的QLable中显示很长的文件名/字符串时,超出QLabel宽度部分将不会显示,此时采取缩短文件名策略(也可实现为字符串滚动动画)可以缓解这一问题.在实现这一想法的过程中 ...
- Delphi的Anymouse方法探秘
匿名函数是用Interface来实现的,具体细节可以看http://www.raysoftware.cn/?p=38匿名函数还是非常方便的.比如自己封装的异步调用.Async(procedure(AP ...