美文网首页
底层原理总结 -- initialize

底层原理总结 -- initialize

作者: 踩坑小分队 | 来源:发表于2020-03-15 13:56 被阅读0次
    • initialize调用时机
      会在类第一次接收到消息的时候调用
    • 调用顺序
      如果父类没有接受过消息,先调用父类的initialize,再调用子类的initialize。
    @interface Person : NSObject
    
    + (void)run;
    
    @end
    
    #import "Person.h"
    
    @implementation Person
    
    + (void)run{}
    
    + (void)initialize {
        NSLog(@"--Person");
    }
    
    @end
    

    当我们第一次调用[Person run]的时候,就会调用initialize方法
    Person调用run方法其实是消息发送机制
    调用run方法的步骤

    isa --> 元类对象 --> 方法列表 --> 找到方法 --> 调用
    如果没有找到方法
    superclass -->方法列表 --> 找到方法 --> 调用

    猜测:
    调用方法的时候,查找方法之前,会判断当前类有没有实例化,如果没有实例化则调用initialize方法

    我们来看下runtime的源码,来分析一下
    既然是查找方法,我们就看下 class_getClassMethod 这个方法的调用
    其实看class_getInstanceMethod 是一样的。因为你会发现

    /***********************************************************************
    * class_getClassMethod.  Return the class method for the specified
    * class and selector.
    **********************************************************************/
    Method class_getClassMethod(Class cls, SEL sel)
    {
        if (!cls  ||  !sel) return nil;
    
        return class_getInstanceMethod(cls->getMeta(), sel);
    }
    

    继续看lookUpImpOrNil方法
    lookUpImpOrForward

    // 如果对象需要实例化,并且对象没有实例化
    if (initialize && !cls->isInitialized()) {
            cls = initializeAndLeaveLocked(cls, inst, runtimeLock);
            // runtimeLock may have been dropped but is now locked again
    
            // If sel == initialize, class_initialize will send +initialize and 
            // then the messenger will send +initialize again after this 
            // procedure finishes. Of course, if this is not being called 
            // from the messenger then it won't happen. 2778172
        }
    

    initializeAndMaybeRelock
    initializeNonMetaClass

    // 如果说当前类的父类存在,并且父类没有实例化。递归调用`initializeNonMetaClass`方法
    // Make sure super is done initializing BEFORE beginning to initialize cls.
        // See note about deadlock above.
        supercls = cls->superclass;
        if (supercls  &&  !supercls->isInitialized()) {
            initializeNonMetaClass(supercls);
        }
    

    initializeNonMetaClass方法中通过objc_msgSend调用SEL SEL_initialize

    callInitialize(cls);
    
    void callInitialize(Class cls)
    {
        ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);
        asm("");
    }
    

    所以initialize方法的调用顺序是,先递归调用父类的initialize<如果父类没有初始化的前提下>然后再调用自己的initialize


    和load方法的一些对比

    1、Category中有load方法吗?load方法是在什么时候调用的?load方法能继承吗?

    Category中有load方法
    load方法在runtime加载类和分类的时候调用,先调用类的,再调用分类的
    load方法是可以继承的,但是一般都是让系统自己去调用

    2、loadinitialize方法有啥区别?
    • 调用方式:

    load是根据函数的地址直接调用的
    initialize是通过runtimeobjc_msgSend进行调用的

    • 调用时刻:

    load是在runtime加载类或者分类的时候调用的,先调用类的load方法,再按照编译顺序调用分类的load方法<只会调用一次>
    initialize是在类第一次接收消息的时候调用的,每一个类只会调用一次initialize方法,父类可能会调用多次,如果子类没有重新initialize方法,就会调用多次。

    3、loadinitialize方法在Category中的调用顺序是什么?

    load:

    1.load方法按照编译顺序,调用load方法

    initialize:

    1.最后编译的分类,会被调用。和一般的类方法一样

    4、loadinitialize方法,出现继承时他们之间的调用顺序?

    load:

    1.调用类的load方法
    2.按照编译顺序调用load方法
    3.调用子类的load方法之前,先调用父类的load方法

    initialize:

    1.先初始化父类
    2.再初始化子类<有可能调用的是父类的initialize,如果子类没有实现>

    相关文章

      网友评论

          本文标题:底层原理总结 -- initialize

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