一、性能优化相关涉及到的硬件
1、CUP(中央处理器)
对象的销毁和创建、对象属性的调整、布局计算、文本计算、文本排版、图片格式的转换和解码 和 图像的绘制等。
2、GPU(图形处理器)
纹理的渲染;
Mac的缓存是分为前后帧缓存,可以增加处理速度。

卡顿的原因:
CPU
计算之后,GPU
进行渲染,如果计算和渲染的时间太长,在还没有处理完上一帧,下一帧出现,就会接着显示上一帧,就出现了掉帧的情况。
解决卡顿方法:
尽量减少CUP
和GUP
的资源消耗,保证正常的流畅。我们屏幕显示,一般保证在一秒钟60帧,就不会产生卡顿的现象。
二、优化从哪些方面着手
CUP:
- 尽量用轻量级的对象,比如用不到的时间处理的地方,可以考虑使用
CALayer
取代UIView
; - 不要频繁的调用
UIVIew
的相关属性,比如frame
、bounds
,transform
等属性,尽量减少不必要的修改; - 尽量提前计算好布局,在有需要时一次性调整对应的属性,不要多次修改属性;
-
Autolayout
会比直接设置frame
消耗更多的CUP
资源; - 图片的size最好刚好跟UIImageView的size保持一致;
- 控制一下线程的最大并发数量;
- 尽量把消耗耗时的操作放到子线程去做:
- 文本处理(尺寸计算、绘制);
- 图片处理(解码、绘制)。很多第三方的框架,都是这样子做的。将
UIImae
转为CGImage
,创建一个CGContextRef
,把CGImage
放到这个谓图上下文中。通过CGContextDrawImage
画在谓图上。最后放到UIImage里,就完成了解码和绘制。
GPU:
- 尽量避免短时间内大量图片的显示, 尽可能将多张图片合成一张来显示;
- GPU能处理的最大尺寸是4096x4096,一旦超过这个尺寸,就会占用CPU的资源进行处理,所以纹理尽量不要超过这个尺寸。
- 尽量减少视图数量和层次;
- 减少透明的视图(
alpha
< 1), 不透明的就设置opaque
为YES
; - 尽量避免出现离屏渲染;
- 需要创建新的缓冲区;
- 离屏渲染的整个过程,需要多次切换上下文环境,从当前屏幕切换到离屏,等到离屏渲染结束后,将离屏缓冲区的渲染结果显示到屏幕上,又需要将上下文环境从离屏切换到当前屏幕。
哪些操作会触发离屏渲染?
- 光栅化:
layer.shouldRasterize = YES
- 遮罩:
layer.mask
\ - 圆角:同时设置
layer.masksToBounds = YES
、layer.cornerRadius
大于0
- 如果你要设置圆角,可以通过
CoreGraphics
绘制裁剪圆角,或者叫美工提供圆角图片。
- 如果你要设置圆角,可以通过
- 阴影:
layer.shadowXXX
- 如果设置了
layer.shadowPath
就不会产生离屏渲染。
- 如果设置了
三、卡顿检查
- 平时我们所说的 “卡顿” 主要是因为在主线程执行了比较耗时的操作;
- 可以添加
Observe
到主线程RunLoop
中,通过监听RunLoop
状态切换的耗时,以达到监控卡顿的目的;
这里有一个三方的框架LXDAppFluecyMonitor大家可以尝试了解哈。
四、耗电的主要来源
- 尽可能降低
CUP
、GPU
功耗 - 少用定时器
- 优化
I/O
操作- 尽量不要频繁写入小数据,最好批量一次性写入
- 写入大量重要数据时,考虑用
dispathch_io
, 其提供了基本GCD
的一部操作文件I/O
的API
,用dispathch_io
系统会优化磁盘访问; - 数据量比较大的,建议使用数据库(比如
SQLite
、CoreData
)
- 网络优化
- 减少、压缩网络数据(
XML
体积比较大、JSON
体积比较少); - 如果多次请求的相同的,尽量使用缓存;
- 使用断点续传,否则网络不稳定的时候可能会多次传输相同内容;
- 网络不可用时,不要尝试执行网络请求;
- 让用户可以取消长时间运行或者速度很慢的网络操作,设置合适的超时时间;(比如网络慢时,你加载数据有蒙版,用户就无法操作,一直在等待网络请求)
- 尽量批量传输,比如:下载视频流时,不要传输很小的数据包,直接下载整个文件或者一大块一大块的下载。如果下载广告,一次性下载一些,然后再慢慢展示。如果下载电子邮件,一次性下载多封,不要一封一封的下载;
- 减少、压缩网络数据(
- 定位优化
- 如果只是需要快速确定用户位置,最好使用
CLLocationManager
的requestLocation
方法。定位完成后,会自动让定位硬件断电; - 如果你应用不是导航应用,尽量不要实时更新位置,定位完毕就关掉定位服务;
- 尽量降低定位精度,比如:尽量不要使用精度最高的
KCLLocationAccuracyBest
; - 需要后台定位时,尽量设置
pausesLocationUpdatesAutomatically
为YES
,如果用户不太可能移动的时候,体统会自动暂停位置更新;
- 如果只是需要快速确定用户位置,最好使用
五、APP的启动
大致分为3个阶段:
- dyld:Apple的动态链接器,可以用来装载Mach-O文件(可执行文件、动态库等);
- runtime:
- main:
启动APP时,dyld所做的事情有:
- 装载APP的可执行文件,同时会递归加载所有依赖的动态库;
- 当dyld把可执行文件,动态库都装载完毕后,会通过Runtime进行下一步处理;
启动APP时,runtime所做的事情有:
- 顶用
map_images
进行可执行文件内容的解析和处理; - 在
load_images
中调用call_load_methods
,调用所有Class
和Category
的+load
方法; - 进行各种
objc
结构的初始化(注册objc
类,初始化类对象等等); - 调用
C++
静态初始化器和__attribute__((contructor))
修饰的函数;
到此为止,可执行文件和动态库中所有的符号(Class
、Protocol
、Selector
、IMP
、
...)都已经按格式成功加载到内存中,被runtime
所管理。
启动APP时,main所做的事情有:
- APP的启动由
dyl
d主导,将可执行文件加载到内存,顺便加载所有依赖的动态库; - 并由
runtime
负责加载成objc
定义的结构; - 所有初始化工作结束后,
dyld
就会调用main
函数; - 接下来就是
UIApplicationMain
函数,AppDelegat
e的application:didFinishLaunchingWithOptions:
方法。
APP的启动分为2种:
- 冷启动:从零开始启动APP;
- 热启动:APP已经在内存中,在后台存活着,再次点击图标启动APP;
APP启动时间优化,主要是针对冷启动进行优化。
通过添加环境变量可以打印出APP的启动时间分析(Edit scheme -> Run -> Arguments):
- name:
DYLD_PRINT_STATISTICS
value:1
(主要是main函数之前的消耗时间) - 如果需要更详细的信息,将
DYLD_PRINT_STATISTICS
替换为DYLD_PRINT_STATISTICS_DETAILS
一般启动时间在400毫秒内都是能接受的。
优化dyld、runtime、main
- dyld:
- 减少动态库、合并一些动态库(定期清理不必要的动态库);
- 减少
ObjC
类、分类的数量、减少Selector
数量(定期清理不必要的类、分类); - 减少
C++
虚函数数量; -
Swift
尽量使用struct
- runtime:
- 用
+initialize
方法和dispathch_onec
取代所有的__attrbute__((constructor))
、C++静态构造器
、ObjC的+load
;
- 用
- main:
- 在不影响用户体验的前提下,尽可能将一些操作延迟,不要全部放在
finishLaunching
方法中; - 按需加载;
- 在不影响用户体验的前提下,尽可能将一些操作延迟,不要全部放在
六、安装包瘦身
安装包主要包括:可执行文件、资源
- 可执行文件:
- 编译器优化,比如:
-
Strip Linked Product
、Make Strings Read-Only
、Symbols Hidden by Default
设置为YES
;(新项目一般默认都是YES
,只有老项目可能没有) - 去掉异常支持,
Enable C++ Exceptions
、Enable Objective-C Exceptions
设置为NO
,Other C Flags
添加-fno-exceptions
;(这个到 Build Settings 里面搜索)
-
- 利用AppCode检测未使用代码:菜单栏 -> Code -> Inspect Code;
- 编写LLVM插件检测重复代码、未被使用的代码;
- 编译器优化,比如:
- 资源:
- 采取无损压缩;
- 去除没有用到的资源:第三方库LSUnusedResources;
网友评论