刨根问底load initilze方法

2016-11-11  本文已影响86人  有一种再见叫青春

首先了解一下应用启动后,做了什么

main.m 中的 main() 是程序的入口,但在进入 main 函数之前,程序就执行了很多代码(不然也不会启动那么久)。
将程序依赖的动态链接库加载进内存
加载可执行文件中的所有符号、代码
runtime 解析被编译过的符号代码,遍历所有 Class,按继承层级依次调用Class 的 load 方法和其 Category 的 load 方法。

详细的步骤可以参考sunnyxx大神的这篇文章;

Load

Load方法在文件被程序装载时调用.也就是在Compile Sources中出现的文件.与<em>这个类是否被用到无关</em>.

调用规则

<pre>
2016-11-11 14:28:39.807 [1734:818024] +[FatherViewController load]
2016-11-11 14:28:39.808 [1734:818024] +[SonViewController load]
2016-11-11 14:28:39.808 [1734:818024] +[ViewController load]
2016-11-11 14:28:39.808 [1734:818024] +[AppDelegate load]
2016-11-11 14:28:39.808 [1734:818024] +[ClassMian load]

2016-11-11 14:28:39.809 [1734:818024] +[SonViewController(Category_son) load]
2016-11-11 14:28:39.809 [1734:818024] +[FatherViewController(Category_01) load]
2016-11-11 14:28:39.809 [1734:818024] +[ViewController(Category) load]
</pre>

如果感兴趣 可以自己创建一些类和类别 展开 Build Phases 的 Compile Sources 调用下各个文件的顺序 尝试一下各种情况下load的调用顺序.主要太没技术含量了,就不详细写这些了 = =.

结论

<ul>
<li> 执行子类的 load 之前,当父类未加载时,先执行父类的 load 方法。</li>
<li>分类的 load 方法统一在最后执行</li>
<li>优先满足以上两条,再满足按 Compile Sources 的顺序执行 load 方法。</li></ul>

需要注意的是子类如果没有实现load方法,那么就不会调用父类的load方法
由于调用load方法时的环境很不安全,我们应该尽量减少load方法的逻辑。另一个原因是load方法是线程安全的,它内部使用了锁,所以我们应该避免线程阻塞load方法中。

initialize

这个方法是在第一次给某个类发送消息时调用(实例化对象),并且只会调用一次.这个类方法是惰性调用,如果一个类一直没有被用到,此方法也不会执行.

initiialze方法的执行顺序

<pre>**2016-11-11 15:19:18.029 [1850:1017547] +[FatherViewController load]** **2016-11-11 15:19:18.031 [1850:1017547] +[FatherViewController(Category_01) initialize]** **2016-11-11 15:19:18.031 [1850:1017547] +[SonViewController(Category_son) initialize]** **2016-11-11 15:19:18.031 [1850:1017547] +[SonViewController load]** **2016-11-11 15:19:18.031 [1850:1017547] +[ViewController load]** **2016-11-11 15:19:18.031 [1850:1017547] +[AppDelegate load]** **2016-11-11 15:19:18.031 [1850:1017547] +[mianClass load]** **2016-11-11 15:19:18.032 [1850:1017547] +[SonViewController(Category_son) load]** **2016-11-11 15:19:18.032 [1850:1017547] +[FatherViewController(Category_01) load]** **2016-11-11 15:19:18.032 [1850:1017547] +[ViewController(Category) load]** **2016-11-11 15:19:18.032 [1850:1017547] +[AppDelegate initialize]** **2016-11-11 15:19:18.085 [1850:1017547] +[ViewController(Category) initialize]**</pre>

从结果来看,先执行了FatherViewController(Category_01) initialize, 在执行了SonViewController(Category_son) initialize,而SonViewController load最后执行.也就是说load方法还未执行也不会影响这个类的使用.

下面来看一看initialize方法的继承问题

从上面打印结果可以看出执行子类 initialize 的时候会先执行其父类的 initialize。且 category 的覆写效应对 load 方法无效,但对 initialize 方法有效。下面将子类的initialize注释,重写其initialze方法

<pre>+ (void)initialize { NSLog(@"调用者:%@ 调用方法:%s",NSStringFromClass(self), __func__);}</pre>

子类会继承父类的 initialize 。当执行完父类的 initialize 方法,准备执行子类的 initialize 方法时,会根据继承链找到父类的 initialize 执行。

什么时候使用initialize

initialize方法主要用于对一些不好方便在编译期初始化的对象进行赋值,如NSMutableArray的实例化方法,在使用此方法时需要注意此方法是被调用多次的 是否需要添加dispatch_once.

总结

1.loadinitialize方法都会在实例化对象前调用, 以main函数为分水岭,load在mian之前,initialize在main之后.
2.loadinitialize方法调用父类的方法是隐性的自动调用,即使子类没有实现initialize方法也会调用父类的方法,load方法则不会调用父类.
3.load方法常常用于黑魔法的实现,initialize方法用于初始化全局变量
4.load initialize方法都是线程安全的!需避免复杂操作.

上一篇下一篇

猜你喜欢

热点阅读