这是戴老师发布的第三篇,正经发布的第一篇。看了1天以后我就想说,我要不还是去卖人参吧,太难了!这以后我要是全学会了我有立刻辞职去阿里的冲动。当然了,我除了在学习里面的知识,我还在想1个问题。
为什么他会我不会?
这个问题的扯淡程度直逼他的答案的扯淡程度,我觉得我不会的原因是因为很大一段时间我觉得学了没用。按照文章的优化方法,我们那个小破app启动顶多能缩短个几百ms,因为本来app就简单。但是缩短个几百ms对于1个app没用对于技术有用么?这要涉及到学习方法。
我自己总结的学习方法是这样的:比如你要学一门新的语言,你要买1本基础书。有人说基础啥的你上网查不就得了?但是别忘了,你没学过你连查啥都不知道。还有就是学基础的时候别查的太深,这个阶段以用为主。等过了这个阶段,开始查漏补缺,进行深入进阶。这也是我学习戴老师课程的原因。所以缩短个几百ms,可能用app的人感觉不到,但是这个技术不理解,我看我下一章也不用看了。
正文开始,app的启动过程
我们首先将app分为冷启动和热启动,热启动顾名思义,人家都热了,说明启动一遍了,可能在后台啥的,这个阶段能做的事很少,我们不研究。我们从冷启动开始说,冷启动我们又分为三个阶段
1. main()函数执行前。这个阶段我们主要有以下几个部分(1)加载可执行二进制文件mach-o文件(昨天的查漏补缺一直就是针对的这个)(2)加载动态库链接器dyld,dyld是个专门用来加载动态链接库的库。执行从d yld开始,dyld从可执行文件的依赖开始,递归加载所有的依赖动态链接库。动态链接库包括iOS用到的所有系统Framework,加载OCruntime用到的libObjc,系统级别的libSystem,例如libdispatch(GCD)和libsystem_blocks(Block),进行 rebase 指针调整和 bind 符号绑定 (3)Objc进行类的注册,确定方法的唯一性 (4)初始化执行load方法,attribute((constructor)) 修饰的函数,创建C++全局静态变量。
好了,这些东西就足够我们研究一阵子的了。我们先说一下什么是Mach-o文件,mach-o就是Mach Object。官方给的Mach-o文件非常复杂,里面有啥啥啥的看不懂的东西,就是已经细微到寄存器的东西,我实在研究不通。就只按我自己的理解来说,Mach-o文件其实就是一些文件的集合:里面有二进制文件,类型为Excutable,里面还有动态库文件dylib,里面还有捆绑包,bundle包,一种特别的动态库,只能在运行时运行。Framework文件,是包含资源或者头文件的静态库或者动态库。那么mach-o文件在哪里看呢,我找了半天就是没找到。后来才知道,一般的framework里面都有.o文件但是你是看不到的,你需要用一个叫MachOView的软件打开它才能看见里面的.o文件否则你看到的可能就是这样的
这是百度人脸识别的SDK,反正我是没找到什么.o文件。但是我们好像换一种方法看不到,能摸到:
这样我们确实看到它是1个mach-o文件了哈,但是再深入的我就没有研究了。
下面我们在研究下什么叫rebase指针调整和bind符号绑定。首先我们确定一下这个是动作是谁做的。是dyld做的。dyld是什么?动态库连接器。怎么样链接动态库?为什么要链接动态库?因为加载了mach-o二进制文件后,动态库是独立的,dyld要将所有动态库绑定起来。mach-o动态库上面要写上要绑定的动态库的指针和数据,用来修正(fix-up),修正有两种类型,一种叫rebasing,一种叫binding。为什么要修正呢?据说在iOS4.3以前不需要修正,后来有了ASLR(address space layoutrandomization)的存在,可执行文件和动态链接库在虚拟内存中的加载地址每次启动都不固定,所以需要这2步来修复镜像中的资源指针,来指向正确的地址。 rebase修复的是指向当前镜像内部的资源指针; 而bind指向的是镜像外部的资源指针。 第三点进行类的注册优化起来就很明了,就是我们尽可能减少类的数量,就可以减少加载时间。第四个,初始化执行load方法也很简单就是少些+load()方法,attribute((constructor)) 修饰的函数调用就是1个函数可以在main函数之前调用,有什么作用还不清楚,我没用过,如图:
C++全局变量就类似于这种,如图:
2. main()函数执行后。main() 函数执行后的阶段,指的是从 main() 函数到 appDelegate 的 didFinishLaunchingWithOptions方法里首屏渲染相关方法执行完成。这里面要写的东西我们大家就很熟悉了,一般就是初始化首屏架构,一些第三方的初始化,但是其中我们应该区分开,哪些是首屏渲染之前应该写的,哪些可以在使用功能的时候才开始。另外关于这个首屏初始化没有1个固定的说法,有些人认为到首页viewDidAppear出现了才算,有的人认为走完了didFinishLaunchingWithOptions就算,看个人理解吧。