美文网首页
+initialize方法的原理

+initialize方法的原理

作者: 85ca4232089b | 来源:发表于2020-03-19 14:28 被阅读0次

    initialize源码分析。objc源码下载地址

    IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
    {
        const IMP forward_imp = (IMP)_objc_msgForward_impcache;
        IMP imp = nil;
        Class curClass;
    
        runtimeLock.assertUnlocked();
    
        // 小概率事件
        if (fastpath(behavior & LOOKUP_CACHE)) {
            imp = cache_getImp(cls, sel);
            if (imp) goto done_nolock;
        }
        runtimeLock.lock();
    
        checkIsKnownClass(cls);
    // 很可能 cls 是有值的,编译器可以不用每次都读取 return nil 指令(小概率事件)
        if (!cls->isRealized()) {
            realizeClass(cls);
        }
      if (slowpath(!cls->isRealized())) {
            cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
            // runtimeLock may have been dropped but is now locked again
        }
    
        if (initialize  &&  !cls->isInitialized()) {
            runtimeLock.unlock();
            _class_initialize (_class_getNonMetaClass(cls, inst));
            runtimeLock.lock();
            // 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
        }
    

    首先我们会发现 initialize 方法出现在 lookUpImpOrForward方法中.
    • lookUpImpOrForward 方法是在方法查找转发流程当中,这也就说明了initialize方法是在main函数之后调用的

    1. 会进行判断当前的cls有没有实现initialize方法,
        if (initialize  &&  !cls->isInitialized()) {
            runtimeLock.unlock();
            _class_initialize (_class_getNonMetaClass(cls, inst));
            runtimeLock.lock();
        }
    

    • if中的条件是大概率(fastpath:真值判断)还是小概率(slowpath:假值判断)事件,从而让编译器对代码进行优化

    Class _class_getNonMetaClass(Class cls, id obj)
    {
        rwlock_writer_t lock(runtimeLock);
        cls = getNonMetaClass(cls, obj);
        assert(cls->isRealized());
        return cls;
    }
    static Class getNonMetaClass(Class metacls, id inst)
    {
        static int total, named, secondary, sharedcache;
        runtimeLock.assertLocked();
    
        realizeClass(metacls);
    
        total++;
    
        // return cls itself if it's already a non-meta class
        if (!metacls->isMetaClass()) return metacls;
    
        // metacls really is a metaclass
    
        // special case for root metaclass
        // where inst == inst->ISA() == metacls is possible
        if (metacls->ISA() == metacls) {
            Class cls = metacls->superclass;
            assert(cls->isRealized());
            assert(!cls->isMetaClass());
            assert(cls->ISA() == metacls);
            if (cls->ISA() == metacls) return cls;
        }
    }
    

    • _class_getNonMetaClass :给一个非元类对象(类),发送了一个类方法

    1. 如果不是元类,则不应该走下面的逻辑,直接返回
      if (!metacls->isMetaClass()) return metacls;
    2. 如果是元类的元类是自己,如果它的superclass的isa指向自己,则表示是根元类
    3. 然后获取非元类的实例,且不获取子类
        if (inst) {
            Class cls = (Class)inst;
            realizeClass(cls);
            // cls may be a subclass - find the real class for metacls
            while (cls  &&  cls->ISA() != metacls) {
                cls = cls->superclass;
                realizeClass(cls);
            }
            if (cls) {
                assert(!cls->isMetaClass());
                assert(cls->ISA() == metacls);
                return cls;
            }
        }
    
    

    • 如果没有实现_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);
        }
    }
    

    • 给该cls设置flag标示该cls已经调用+initialize初始化过

          lockAndFinishInitializing(cls, supercls);
    

    • callInitialize(Class cls) 通过消息机制调用initialize方法。
    消息发送机制:遍历类的继承关系,依次从子类到父类的方法缓存列表和方法列表中寻找方法,未找到时进行动态方法解析,未能解析是走消息转发机制)

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

    initialize类方法的特点:

    • 即使类文件被引用进项目,但是没有使用,initialize不会被调用
    • 假如这个类放到代码中,而这段代码并没有被执行,这个函数是不会被执行的。
    • 类或者其子类的第一个方法被调用前调用
    • 由于是系统自动调用,也不需要再调用 [super initialize] ,否则父类的initialize会被多次执行

    initialize类方法调用的特点

    • 父类的initialize方法会比子类先执行
    • 子类未实现initialize方法时,会调用父类initialize方法,子类实现initialize方法时,会覆盖父类initialize方法.
    • 当有多个Category都实现了initialize方法,会覆盖类中的方法,只执行一个(会执行Compile Sources 列表中最后一个Category 的initialize方法)

    总结:

    • load和initialize方法都会在实例化对象之前调用
    • load执行在main函数以前,initialize执行main函数之后
    • 这两个方法会被自动调用,不能手动调用它们。
    • load和initialize方法都不用显示的调用父类的方法而是自动调用
    • 子类没有initialize方法也会调用父类的方法,而load方法则不会调用父类
    • initialize方法对一个类而言只会调用一次(Person、或者是Person+Category)都是一个Perosn类。load方法则是每个都会调用,只要你写了load方法,添加到工程都会实现。
    • load方法通常用来进行Method Swizzle,initialize方法一般用于初始化全局变量或静态变量。
    • load和initialize方法内部使用了锁,因此它们是线程安全的。实现时要尽可能保持简单,避免阻塞线程,不要再使用锁。
    load方法解析

    相关文章

      网友评论

          本文标题:+initialize方法的原理

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