探索 +initialize 底层调用机制 并与+load 比较

前言

在上一篇文章中(手把手带你探索load底层原理)探索了load的调用机制,本文是探索一下initialize的调用机制,并比较一下异同点。 +initialize其实在平时开发中用的较少,通常用来初始化常量,不过面试中常会问到它与+load的区别。面试

initialize调用规则

  1. +initialize 方法是在类或它的子类收到第一条消息以前被调用的,这里所指的消息包括实例方法和类方法的调用。也就是说 +initialize 方法是以懒加载的方式被调用的,若是程序一直没有给某个类或它的子类发送消息,那么这个类的 +initialize 方法是永远不会被调用的。
  2. 当子类没有实现+initialize或者子类在+initialize中显式的调用了[super initialize],那么父类的+initialize方法会被调用屡次。
  3. 在分类实现+initialize,会只执行分类的+initialize
  4. 类的+initialize方法在全部父类的+initialize方法调用以后调用

验证调用规则

此次是在objc源码中直接调试代码,在我提供的源码里新建一个target, 以下图 函数

接下来建立Person类,实现loadinitialize方法,编译运行咱们刚才建立的target post

运行结果只执行了load方法,并无执行initialize方法,因此可以获得结论:load在文件被加载时就执行了,initialize不主动调用atom

对于本文开头的几个结论,能够在这里都简单用代码验证一遍,我这里就再也不去一一验证了,直接开始探索源码。spa

探索

我在load里打印了一下self,发现initialize被调用了,那么看看断点处的initialize 3d

发现这里其实就进入到了runtime的消息查找流程,这里直接来到第三步,这里判断是否类已经初始化,没有初始化就作初始化操做。因此在这里能够验证开头的结论一,它是收到类的第一条消息后才调用的。 调试

看看_class_initialize函数code

void _class_initialize(Class cls)
{
    assert(!cls->isMetaClass());

    Class supercls;
    bool reallyInitialize = NO;

    // Make sure super is done initializing BEFORE beginning to initialize cls.
    // See note about deadlock above.
    supercls = cls->superclass;
    if (supercls  &&  !supercls->isInitialized()) {
        _class_initialize(supercls);
    }
    
    // Try to atomically set CLS_INITIALIZING.
    {
        monitor_locker_t lock(classInitLock);
        if (!cls->isInitialized() && !cls->isInitializing()) {
            cls->setInitializing();
            reallyInitialize = YES;
        }
    }
    //其他代码省略
    callInitialize(cls);
复制代码
  • 这里有一个标识符reallyInitialize,在cls->setInitializing()(给类的isa设置RW_INITIALIZING标识),设置完后改成truecdn

  • 这里有拿到 supercls,而后判断是否存在和是否初始化完成,未初始化则调用本身自己这个函数_class_initialize,其实就是一个递归,用来确保全部父类的initialize已经执行完,再执行当前类,这里和以前探索load的时候的递归调用父类load的方法原理相同。因此在这里能够验证开头的结论四:类的+initialize方法在全部父类的+initialize方法调用以后调用。blog

void callInitialize(Class cls) {
    ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);
    asm("");
}
复制代码
  • 最后会调用callInitialize, 使用了发送消息 objc_msgSend 的方式对 +initialize 方法进行调用。也就是说 +initialize 方法的调用与普通方法的调用是同样的,走的都是发送消息的流程。换言之,若是子类没有实现 +initialize 方法,那么继承自父类的实现会被调用;因此有告终论三:若是一个类的分类实现了 +initialize 方法,那么就会对这个类中的实现形成覆盖。
  • 所以,这里验证了开头的结论二:若是一个子类没有实现 +initialize 方法,那么父类的实现是会被执行屡次的

总结

相关文章
相关标签/搜索