iOS性能优化系列
一:性能优化策略
这一系列文章是我的读书笔记,整理一下,也算是温故而知新。
性能问题的处理流程
- 发现/重现问题
- 利用工具剖析
- 形成假设
- 改进代码和设计
在以上的四个步骤中循环反复,直到问题解决。
Profile!不要猜!
性能优化的主要策略:
- 不要做无用功:不要在启动时花几百ms来做logging,不要为同样的数据做多次查询
- 试图重用:对于创建过程昂贵的对象,要重用而不是重新创建
- Table View的cell
- Date/Number的formatter
- 正则表达式
- SQLite语句
- 使用更快的方式设计、编程:选择正确的集合对象和算法来进行编程、选择适合的数据存储格式(plist、SQLite)、优化SQLite查询语句
- 事先做优化
- 对于昂贵的计算,要进行事先计算。iCal中的重复事件,是预先计算出来的,并保存到数据库中。
- 事先计算并缓存一些对象,可能会占用大量的内存。注意不要将这些对象声明为static并常驻内存。
- 事后做优化:异步加载、懒加载
- 为伸缩性而做优化:当数据有10条、100条、1000条甚至更多的时候,应用程序的性能不应该对应的呈数量级式的增长,否则无法使用。
说起来惭愧,我真的很少遇到性能问题。以前假设中的性能问题,很多是根本不存在的。事前计划也杜绝了不了性能问题的产生,所以不如暂时忘记它吧。当然对于一些常识性的提高性能的设计,仍然是必须的。
二:iOS应用启动速度优化
很多app的开发者都不重视app的启动速度,这对于碎片化使用情景的用户来说,简直是灾难。
iOS应用的启动速度
应用启动时,会播放一个放大的动画。iPhone上是400ms,iPad上是500ms。最理想的启动速度是,在播放完动画后,用户就可以使用。
如果应用启动过慢,用户就会放弃使用,甚至永远都不再回来。抛开代码不谈,如果抱着PC端游和单机游戏的思维,在游戏启动时强加公司Logo,启动动画,并且用户不可跳过,也会使用户的成功使用率大大降低。
iOS系统的“看门狗"
为了防止一个应用占用过多的系统资源,开发iOS的苹果工程师门设计了一个“看门狗”的机制。在不同的场景下,“看门狗”会监测应用的性能。如果超出了该场景所规定的运行时间,“看门狗”就会强制终结这个应用的进程。开发者们在crashlog里面,会看到诸如0x8badf00d
这样的错误代码(“看门狗”吃了坏的食物,它很不高兴)。
场景 | “看门狗”超时时间 |
---|---|
启动 | 20秒 |
恢复运行 | 10秒 |
悬挂进程 | 10秒 |
退出应用 | 6秒 |
后台运行 | 10分钟 |
值得注意的是,Xcode在Debug的时候,会禁止“看门狗”。
如何测试启动时间
两种方法:一种使用NSLog,另外一种使用Time Profiler。
- 使用Time Profiler
- Instruments->Time Profiler
- Profile你的app
- 切换到CPU strategy view,找到你的app启动的第一帧
- 搜索
-[UIApplication _reportAppLaunchFinished]
- 找到包含
-[UIApplication _reportAppLaunchFinished]
的最后一帧,即可计算出启动时间
iOS App启动过程
- 链接并加载Framework和static lib
- UIKit初始化
- 应用程序callback
- 第一个Core Animation transaction
链接并加载Framework及static lib时需要注意:
- 每个Framework都会增加启动时间和占用的内存
- 不必要的Framework,不要链接
- 必要的Framework,不要票房为Optional
- 只在使用在Deployment Target之后发布的Framework时,才使用Optional(比如你的Deployment Target是iOS 3.0,需要链接StoreKit的时候)
- 避免创建全局的C++对象
初始化UIKit时需要注意:
- 字体、状态栏、user defaults、main nib会被初始化
- 保持main nib尽可能的小
- User defaults本质上是一个plist文件,保存的数据是同时被反序列化的,不要在user defaults里面保存图片等大数据
应用程序的回调:
application:willFinishLaunchingWithOptions:
- 恢复应用程序的状态
application:didFinishLaunchingWithOptions: