美文网首页
刨根问底load initilze方法

刨根问底load initilze方法

作者: 有一种再见叫青春 | 来源:发表于2016-11-11 16:02 被阅读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方法都是线程安全的!需避免复杂操作.

    相关文章

      网友评论

          本文标题:刨根问底load initilze方法

          本文链接:https://www.haomeiwen.com/subject/ycdfpttx.html