initialize方法底层实现

initialize方法的调用时机

1、initialize在类第一次接收到消息时调用,也就是objc_msgSend()。
2、先调用父类的+initialize,再调用类的initialize。

举例论证:
我们首先给Student类和Person类覆写+initialize方法:

//Person
+ (void)initialize{
    
    NSLog(@"Person + initialize");
}

//Person+Test1
+ (void)initialize{
    
    NSLog(@"Person (Test1) + initialize");
}

//Person+Test2
+ (void)initialize{
    
    NSLog(@"Person (Test2) + initialize");
}

//Student
+ (void)initialize{
    
    NSLog(@"Student + initialize");
}

//Student (Test1)
+ (void)initialize{
    
    NSLog(@"Student (Test1) + initialize");
}

//Student (Test2)
+ (void)initialize{
    
    NSLog(@"Student (Test2) + initialize");
}

我们运行程序,发现什么也没有打印,说明在运行期没有调用+initialize方法。
然后我们给Person类发送消息,也就是调用函数:

[Person alloc];

打印结果:

2018-07-25 18:34:14.648279+0800 interview - Category[17187:473502] Person (Test2) + initialize
2018-07-25 18:34:14.648394+0800 interview - Category[17187:473502] Student (Test1) + initialize

我们看到不仅调用了Student类的initialize方法,而且还调用了Student类的父类,Person类的方法,因此我们猜测在调用类的initialize方法之前会先调用父类的initialize方法。

通过runtime源码论证一下我们上面的结论:

initialize方法底层实现_第1张图片
31.png
这个代码说明了每个类的+initialize方法只会被调用一次。

我们点进_class_initialize (_class_getNonMetaClass(cls, inst));寻找真正的实现:
initialize方法底层实现_第2张图片
32.png

然后我们通过callInitialize(cls);查看具体的调用
initialize方法底层实现_第3张图片
33.png

这样一来+initialize方法的调用过程就很清楚了。

+initialize的调用过程:

1、如果本类和父类都实现了initialize方法,初始化本类时,会先初始化父类(即调用父类的initialize方法),然后再调用本类的initialize方法;
2、如果本类没有实现initialize方法,父类实现了initialize方法,则多个子类初始化时会多次调用父类的initialize方法,但是本质上只有第一次initialize方法是初始化父类,后面几个initialize都是方法的调用,即子类没有实现,通过superclass到父类里查找。

伪代码说明:

BOOL studentInitialized = NO;
    BOOL personinitialized = NO;
    BOOL teacherInitialized = NO;
    
    [Student alloc];
    //判断Student类是否初始化了,这里Student类还没有被初始化,所以进入条件语句。
    if(!studentInitialized){
        //判断Student类的父类Person类是否初始化了
        if(!personinitialized){
            //这里Person类还没有初始化,就利用objc_msgSend调用initialize方法
            objc_msgSend([Person class], @selector(initialize));
            //变更Person类是否初始化的状态
            personinitialized = YES;
        }
        //利用objc_msgSend调用Student的initialize方法
        objc_msgSend([Student class], @selector(initialize));
        //变更Student是否初始化的状态
        studentInitialized = YES
    }
    
    [Teacher alloc];
    
    //判断Teacher类是否已经初始化了,这里Teacher类还没有初始化,进入条件语句
    if(!teacherInitialized){
        //判断其父类Person类是否初始化了,这里父类已经初始化了,所以不会进入这个条件语句
        if(!personinitialized){
            
            objc_msgSend([Person class], @selector(initialize));
            personinitialized = YES;
        }
        //利用objc_msgSend调用Teacher类的initialize方法
        objc_msgSend([Teacher class], @selector(initialize));
        //变更状态
        teacherInitialized = YES;
    }

上面列出来的是调用initialize的伪代码,下面再详细说明这个过程:

1.Student类收到alloc消息,开始着手准备调用initialize方法。首先判断自己有没有初始化过。
2.判断自己没有初始化过,所以就去找自己的父类Person类,看Person类有没有初始化过,发现Person类也没有初始化过,且Person类也没有父类,多以对Person类使用objc_msgSend([Person class], @selector(initialize))调用Person类的initialize方法。这是第一次调用Person类的initialize方法。
3.父类处理完后,再通过objc_msgSend([Student class], @selector(initialize));调用Student类的initialize方法,但是由于Student类没有实现initialize方法,所以通过其superclass指针找到父类Person类,然后调用了Person类的initialize实现。这是第二次调用Person类的initialize方法。
4.Teacher类收到alloc方法,开始准备调用initialize放啊发。首先判断自己有没有被初始化过。
5.判断自己没有被初始化过后,又开始判断其父类Person类有没有被初始化过,刚刚父类Person类已经被初始化过。
6.于是通过objc_msgSend([Teacher class], @selector(initialize))调用Teacher类的initialize方法。但是由于Teacher类没有实现initialize方法,所以只能通过superclass指针去查找父类有没有实现initialize方法,发现父类Person类实现了initialize方法,于是调用父类的initialize方法。这是第三次调用Person类的initialize方法。

+initialize和+load的一个很大区别是,+initialize是通过objc_msgSend进行调用的,所以有以下特点:

1、如果子类没有实现+initialize方法,会调用父类的+initialize(所以父类的+initialize方法可能会被调用多次)
2、如果分类实现了+initialize,会覆盖类本身的+initialize调用。

你可能感兴趣的:(initialize方法底层实现)