- 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、load
和initialize
方法有啥区别?
- 调用方式:
load
是根据函数的地址直接调用的
initialize
是通过runtime
,objc_msgSend
进行调用的
- 调用时刻:
load
是在runtime
加载类或者分类的时候调用的,先调用类的load
方法,再按照编译顺序调用分类的load
方法<只会调用一次>
initialize
是在类第一次接收消息的时候调用的,每一个类只会调用一次initialize
方法,父类可能会调用多次,如果子类没有重新initialize
方法,就会调用多次。
3、load
和initialize
方法在Category
中的调用顺序是什么?
load
:
1.load方法按照编译顺序,调用load方法
initialize
:
1.最后编译的分类,会被调用。和一般的类方法一样
4、load
和initialize
方法,出现继承时他们之间的调用顺序?
load:
1.调用类的
load
方法
2.按照编译顺序调用load
方法
3.调用子类的load
方法之前,先调用父类的load
方法
initialize:
1.先初始化父类
2.再初始化子类<有可能调用的是父类的initialize
,如果子类没有实现>
网友评论