底层原理总结 -- initialize

2020-03-15  本文已影响0人  踩坑小分队
@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,如果子类没有实现>

上一篇下一篇

猜你喜欢

热点阅读