美文网首页
iOS +initialize()源码分析

iOS +initialize()源码分析

作者: dbmxl | 来源:发表于2019-02-18 21:34 被阅读0次

    +initialize方法

    +initialize方法会在类第一次接收到objc_msgSend消息时调用

    1. 通过递归遍历类的继承关系,先调用父类的+initialize,再调用子类的+initialize。
    2. 每个类只会通过+initialize方法初始化一次。调用前判断flags& RW_INITIALIZE,调用后置位flags标示,防止重复重复调用。

    +initialize方法通过消息发送机制调用

    1. 当类别实现+initialize方法时优先调用类别+initialize方法。
    2. 子类方法列表中没有+initialize时会调用父类+initialize方法。
    3. 子类不实现initialize方法时,父类的+initialize方法会被多次调用。但是此时的调用是实现的子类初始化,而非父类多次初始化。

    源码流程

    1. objc-msg-arm64.s -> ENTRY _objc_msgSend //消息发送入口
    2. CacheLookup //在类的方法缓存列表中查找
    3. CheckMiss //第一次调用时缓存列表未找到
    4. ENTRY __objc_msgSend_uncached //未找到缓存
    5. MethodTableLookup //去类的方法列表中查找
    6. objc-runtime-new.mm -> _class_lookupMethodAndLoadCache3 //调用C方法
    7. lookUpImpOrForward(cls, sel, obj,YES/initialize/, NO/cache/, YES/resolver/); //initialize=YES
    8. void _class_initialize(Class cls) //递归调用初始化
    9. void callInitialize(Class cls) //objc_msgSend(cls, SEL_initialize)

    源码分析

    • _class_lookupMethodAndLoadCache3 消息发送机制入口函数,initialize=YES
    IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)
    {
        return lookUpImpOrForward(cls, sel, obj,YES/*initialize*/, NO/*cache*/, YES/*resolver*/);
    }
    
    • lookUpImpOrForward 方法寻找和转发
    //消息转发时设置initialize==YES
    IMP lookUpImpOrForward(Class cls, SEL sel, id inst, 
                           bool initialize, bool cache, bool resolver)
    {
        ...
        //该类没有调用过+initialize方法时,调用_class_initialize
        if (initialize  &&  !cls->isInitialized()) {
            runtimeLock.unlock();
            //当cls为元类时获取与元类对应的类
            _class_initialize (_class_getNonMetaClass(cls, inst));
            runtimeLock.lock();
        }
        ...
    }
    
    • _class_initialize 递归遍历cls父类
    void _class_initialize(Class cls)
    {
    ...
        supercls = cls->superclass;
        //如果cls有父类,且父类没有+initialize过。递归调用
        if (supercls  &&  !supercls->isInitialized()) {
            //递归调用
            _class_initialize(supercls);
        }
    ...
    @try
        {
            callInitialize(cls);
        }
        @catch (...) {
            ...
        }
        @finally
        {
            // 设置该类flag标示该类已经调用+initialize初始化过
            lockAndFinishInitializing(cls, supercls);
        }
    ...
    }
    
    • callInitialize(Class cls) 通过消息机制调用initialize方法。
      消息发送机制:遍历类的继承关系,依次从子类到父类的方法缓存列表和方法列表中寻找方法,未找到时进行动态方法解析,未能解析是走消息转发机制)
    void callInitialize(Class cls)
    {
      ((void(*)(Class,SEL))objc_msgSend)(cls, SEL_initialize);
    }
    

    相关文章

      网友评论

          本文标题:iOS +initialize()源码分析

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