1.如何提升 tableview
的流畅度?
本质上是降低 CPU、GPU 的工作,从这两个大的方面去提升性能。
-
CPU:对象的创建和销毁、对象属性的调整、布局计算、文本的计算和排版、图片的格式转换和解码、图像的绘制
-
GPU:纹理的渲染
卡顿优化在 CPU 层面
-
尽量用轻量级的对象,比如用不到事件处理的地方,可以考虑使用 CALayer 取代 UIView
-
不要频繁地调用 UIView 的相关属性,比如 frame、bounds、transform 等属性,尽量减少不必要的修改
-
尽量提前计算好布局,在有需要时一次性调整对应的属性,不要多次修改属性
-
Autolayout 会比直接设置 frame 消耗更多的 CPU 资源
-
图片的 size 最好刚好跟 UIImageView 的 size 保持一致
-
控制一下线程的最大并发数量
-
尽量把耗时的操作放到子线程
-
文本处理(尺寸计算、绘制)
-
图片处理(解码、绘制)
-
卡顿优化在 GPU层面
-
尽量避免短时间内大量图片的显示,尽可能将多张图片合成一张进行显示
-
GPU能处理的最大纹理尺寸是 4096x4096,一旦超过这个尺寸,就会占用 CPU 资源进行处理,所以纹理尽量不要超过这个尺寸
-
尽量减少视图数量和层次
-
减少透明的视图(alpha<1),不透明的就设置 opaque 为 YES
-
尽量避免出现离屏渲染
1.预排版,提前计算
在接收到服务端返回的数据后,尽量将 CoreText
排版的结果、单个控件的高度、cell
整体的高度提前计算好,将其存储在模型的属性中。需要使用时,直接从模型中往外取,避免了计算的过程。
尽量少用 UILabel
,可以使用 CALayer
。避免使用 AutoLayout
的自动布局技术,采取纯代码的方式
2.预渲染,提前绘制
例如圆形的图标可以提前在,在接收到网络返回数据时,在后台线程进行处理,直接存储在模型数据里,回到主线程后直接调用就可以了
避免使用 CALayer 的 Border、corner、shadow、mask 等技术,这些都会触发离屏渲染。
3.异步绘制
4.全局并发线程
5.高效的图片异步加载
5.如何有效降低 APP
包的大小?
降低包大小需要从两方面着手
可执行文件
-
编译器优化
-
Strip Linked Product、Make Strings Read-Only、Symbols Hidden by Default 设置为 YES
-
去掉异常支持,Enable C++ Exceptions、Enable Objective-C Exceptions 设置为 NO, Other C Flags 添加 -fno-exceptions
-
-
利用 AppCode 检测未使用的代码:菜单栏 -> Code -> Inspect Code
-
编写LLVM插件检测出重复代码、未被调用的代码
资源
资源包括 图片、音频、视频 等
-
优化的方式可以对资源进行无损的压缩
6.日常如何检查内存泄露?
目前我知道的方式有以下几种
-
Memory Leaks
-
Alloctions
-
Analyse
-
Debug Memory Graph
-
MLeaksFinder
泄露的内存主要有以下两种:
-
Laek Memory
这种是忘记Release
操作所泄露的内存。 -
Abandon Memory
这种是循环引用,无法释放掉的内存。
上面所说的五种方式,其实前四种都比较麻烦,需要不断地调试运行,第五种是腾讯阅读团队出品,效果好一些,感兴趣的可以看一下这两篇文章:
9.什么是 离屏渲染
?什么情况下会触发?该如何应对?
离屏渲染就是在当前屏幕缓冲区以外,新开辟一个缓冲区进行操作。
离屏渲染出发的场景有以下:
-
圆角 (maskToBounds并用才会触发)
-
图层蒙版
-
阴影
-
光栅化
为什么要避免离屏渲染?
CPU
GPU
在绘制渲染视图时做了大量的工作。离屏渲染发生在 GPU
层面上,会创建新的渲染缓冲区,会触发 OpenGL
的多通道渲染管线,图形上下文的切换会造成额外的开销,增加 GPU
工作量。如果 CPU
GPU
累计耗时 16.67
毫秒还没有完成,就会造成卡顿掉帧。
圆角属性
、蒙层遮罩
都会触发离屏渲染。指定了以上属性,标记了它在新的图形上下文中,在未愈合之前,不可以用于显示的时候就出发了离屏渲染。
-
在OpenGL中,GPU有2种渲染方式
-
On-Screen Rendering:当前屏幕渲染,在当前用于显示的屏幕缓冲区进行渲染操作
-
Off-Screen Rendering:离屏渲染,在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作
-
-
离屏渲染消耗性能的原因
-
需要创建新的缓冲区
-
离屏渲染的整个过程,需要多次切换上下文环境,先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上,又需要将上下文环境从离屏切换到当前屏幕
-
-
哪些操作会触发离屏渲染?
-
光栅化,layer.shouldRasterize = YES
-
遮罩,layer.mask
-
圆角,同时设置 layer.masksToBounds = YES、layer.cornerRadius大于0
-
考虑通过 CoreGraphics 绘制裁剪圆角,或者叫美工提供圆角图片
-
阴影,layer.shadowXXX,如果设置了 layer.shadowPath 就不会产生离屏渲染
-
6.如何高性能的画一个圆角?
视图和圆角的大小对帧率并没有什么卵影响,数量才是伤害的核心输出
label.layer.cornerRadius = 5 label.layer.masksToBounds = true
首先上面的方式是不可取的,会触发离屏渲染。
-
如果能够只用
cornerRadius
解决问题,就不用优化。 -
如果必须设置
masksToBounds
,可以参考圆角视图的数量,如果数量较少(一页只有几个)也可以考虑不用优化。 -
UIImageView
的圆角通过直接截取图片实现,其它视图的圆角可以通过Core Graphics
画出圆角矩形实现。
12.如何优化 APP
的电量?
程序的耗电主要在以下四个方面:
-
CPU 处理
-
定位
-
网络
-
图像
优化的途径主要体现在以下几个方面:
-
尽可能降低 CPU、GPU 的功耗。
-
尽量少用 定时器。
-
优化 I/O 操作。
-
不要频繁写入小数据,而是积攒到一定数量再写入
-
读写大量的数据可以使用 Dispatch_io ,GCD 内部已经做了优化。
-
数据量比较大时,建议使用数据库
-
-
网络方面的优化
-
减少压缩网络数据 (XML -> JSON -> ProtoBuf),如果可能建议使用 ProtoBuf。
-
如果请求的返回数据相同,可以使用 NSCache 进行缓存
-
使用断点续传,避免因网络失败后要重新下载。
-
网络不可用的时候,不尝试进行网络请求
-
长时间的网络请求,要提供可以取消的操作
-
采取批量传输。下载视频流的时候,尽量一大块一大块的进行下载,广告可以一次下载多个
-
-
定位层面的优化
-
如果只是需要快速确定用户位置,最好用 CLLocationManager 的 requestLocation 方法。定位完成后,会自动让定位硬件断电
-
如果不是导航应用,尽量不要实时更新位置,定位完毕就关掉定位服务
-
尽量降低定位精度,比如尽量不要使用精度最高的 kCLLocationAccuracyBest
-
需要后台定位时,尽量设置 pausesLocationUpdatesAutomatically 为 YES,如果用户不太可能移动的时候系统会自动暂停位置更新
-
尽量不要使用 startMonitoringSignificantLocationChanges,优先考虑 startMonitoringForRegion:
-
-
硬件检测优化
-
用户移动、摇晃、倾斜设备时,会产生动作(motion)事件,这些事件由加速度计、陀螺仪、磁力计等硬件检测。在不需要检测的场合,应该及时关闭这些硬件
-