iOS性能优化系列二:iOS应用启动速度优化

很多app的开发者都不重视app的启动速度,这对于碎片化使用情景的用户来说,简直是灾难。

iOS应用的启动速度

应用启动时,会播放一个放大的动画。iPhone上是400ms,iPad上是500ms。最理想的启动速度是,在播放完动画后,用户就可以使用。

如果应用启动过慢,用户就会放弃使用,甚至永远都不再回来。抛开代码不谈,如果抱着PC端游和单机游戏的思维,在游戏启动时强加公司Logo,启动动画,并且用户不可跳过,也会使用户的成功使用率大大降低。

iOS系统的“看门狗”

为了防止一个应用占用过多的系统资源,开发iOS的苹果工程师门设计了一个“看门狗”的机制。在不同的场景下,“看门狗”会监测应用的性能。如果超出了该场景所规定的运行时间,“看门狗”就会强制终结这个应用的进程。开发者们在crashlog里面,会看到诸如0x8badf00d这样的错误代码(“看门狗”吃了坏的食物,它很不高兴)。




























场景 “看门狗”超时时间
启动 20秒
恢复运行 10秒
悬挂进程 10秒
退出应用 6秒
后台运行 10分钟

值得注意的是,Xcode在Debug的时候,会禁止“看门狗”。

如何测试启动时间

两种方法:一种使用NSLog,另外一种使用Time Profiler。

  • 使用NSLog
1
2
3
4
5
6
7
8
9
10
11
12
CFAbsoluteTime StartTime;
int main(int argc, char **argv) {
StartTime = CFAbsoluteTimeGetCurrent();
// ...
}
- (void)applicationDidFinishLaunching:(UIApplication *)app {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Launched in %f sec", CFAbsoluteTimeGetCurrent() - StartTime);
});
// ...
}
  • 使用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:

我一直认为设计的本质是折衷。当你为了100ms的启动速度优化欢欣不已,而无视那长达10秒的启动动画时,应该想想究竟什么是应该做的。做正确的事情比把事情做好更重要。

附小广告一则:唱吧iOS团队诚招iOS工程师,推荐成功即奖励6000元现金或iPhone 6一部,详见这篇blog