1. load dylibs image

通常的,一个App需要加载100到400个dylibs, 但是其中的系统库被优化,可以很快的加载。 针对这一步骤的优化有:

1.减少非系统库的依赖
2.合并非系统库
3.使用静态资源,比如把代码加入主程序

2. rebase/bind

优化该阶段的关键在于减少__DATA segment中的指针数量。我们可以优化的点有:

1.减少Objc类数量, 减少selector数量
2.减少C++虚函数数量
3.转而使用swift stuct(其实本质上就是为了减少符号的数量)

3. main()调用之前的耗时我们可以优化的点

1.减少不必要的framework,因为动态链接比较耗时
2.check framework应当设为optional和required,如果该framework在当前App支持的所有iOS系统版本都存在,那么就设为required,否则就设为optional,因为optional会有些额外的检查
3.合并或者删减一些OC类,关于清理项目中没用到的类,使用工具AppCode代码检查功能,查到当前项目中没有用到的类如下:
3.1 删减一些无用的静态变量
3.2 删减没有被调用到或者已经废弃的方法
3.3 将不必须在+load方法中做的事情延迟到+initialize中
3.4 尽量不要用C++虚函数(创建虚函数表有开销)

4. main()调用之后的加载时间

在main()被调用之后,App的主要工作就是初始化必要的服务,显示首页内容等。而我们的优化也是围绕如何能够快速展现首页来开展。 App通常在AppDelegate类中的- (BOOL)Application:(UIApplication *)Application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中创建首页需要展示的view,然后在当前runloop的末尾,主动调用CA::Transaction::commit完成视图的渲染。

而视图的渲染主要涉及三个阶段:
1.准备阶段 这里主要是图片的解码
2.布局阶段 首页所有UIView的- (void)layoutSubViews()运行
3.绘制阶段 首页所有UIView的- (void)drawRect:(CGRect)rect运行再加上启动之后必要服务的启动、必要数据的创建和读取,这些就是我们可以尝试优化的地方

因此,对于main()函数调用之前我们可以优化的点有:
1.不使用xib,直接视用代码加载首页视图
2.NSUserDefaults实际上是在Library文件夹下会生产一个plist文件,如果文件太大的话一次能读取到内存中可能很耗时,这个影响需要评估,如果耗时很大的话需要拆分(需考虑老版本覆盖安装兼容问题)
3.每次用NSLog方式打印会隐式的创建一个Calendar,因此需要删减启动时各业务方打的log,或者仅仅针对内测版输出log
4.应用启动时发送的所有网络请求,是否可以统一在异步线程请求

5. 具体优化点

因此,针对于今日头条这个App我们可以优化的点如下:

1.纯代码方式而不是storyboard加载首页UI。
2.对didFinishLaunching里的函数考虑能否挖掘可以延迟加载或者懒加载,需要与各个业务方pm和rd共同check 对于一些已经下线的业务,删减冗余代码。
3.对于一些与UI展示无关的业务,如微博认证过期检查、图片最大缓存空间设置等做延迟加载,对实现了+load()方法的类进行分析,尽量将load里的代码延后调用。
4.上面统计数据显示展示feed的导航控制器页面(NewsListViewController)比较耗时,对于viewDidLoad以及viewWillAppear方法中尽量去尝试少做,晚做,不做。

6.iOS App启动过程

参考

(1) 链接并加载Framework和static lib

(2) UIKit初始化

(3) 应用程序callback

(4) 第一个Core Animation transaction

6.1 链接并加载Framework及static lib时需要注意:

1.每个Framework都会增加启动时间和占用的内存
2.不必要的Framework,不要链接
3.必要的Framework,不要设置为Optional
4.只在使用在Deployment Target之后发布的Framework时,才使用Optional(比如你的Deployment Target是iOS 3.0,需要链接StoreKit的时候)避免创建全局的C++对象

6.2 初始化UIKit时需要注意:

1.字体、状态栏、user defaults、main nib会被初始化
2.保持main nib尽可能的小
3.User defaults本质上是一个plist文件,保存的数据是同时被反序列化的,不要在user defaults里面保存图片等大数据

6.3 应用程序的回调

1.application:willFinishLaunchingWithOptions:
2.恢复应用程序的状态
3.application:didFinishLaunchingWithOptions:

7. WWDC 之优化 App 启动速度

参考

7.1 对动态库加载的时间优化

每个App都进行动态库加载,其中系统级别的动态库占据了绝大数,而针对系统级别的动态库都是经过系统高度优化的,不用担心时间的花费.开发者应该关注于自己集成到App的那些动态库,这也是最能消耗加载时间的地方.对此Apple建议减少在App里开发者的动态库集成或者有可能地将其多个动态库最终集成一个动态库后进行导入, 尽量保证将App现有的非系统级的动态库个数保证在6个以内.

7.2 减少Appp的Objective-C类,分类和的唯一Selector的个数

这样做主要是为了加快程序的整个动态链接, 在进行动态库的重定位和绑定(Rebase/binding)过程中减少指针修正的使用,加快程序机器码的生成.

7.3 减少Objc运行初始化的时间花费

主要是类的注册,分类的注册,唯一选择器的存在,以及涉及子父类内存布局的Non Fragile ivars偏移的更新,都会影响Objective-C运行时初始化的时间消耗.

7.4 使用initialize方法进行必要的初始化工作

用+initialize方法替换调用原先在OC的+load方法中执行初始代码工作,从而加快所有类文件的加载速度.

结尾

1.使用DYLD_PRINT_STATISTICS测试启动加载时间
2.减少自定义的动态库集成
3.精简原有的Objective-C类和代码
4.移除静态的初始化操作
5.使用更多的Swift代码

8. Facebook iOS App如何优化启动时间