一、load方法的调用是在pre-main阶段,在main函数之前,调用顺序是父类->子类->分类,类和分类的load都会执行,因为没有走消息发送流程,直接通过类和函数的IMP发送消息的。
objc源码
//⚠️只贴关键代码
void load_images(const char *path __unused, const struct mach_header *mh){
{
//1⃣️准备所有load方法,
prepare_load_methods((**const** headerType *)mh);
}
//2⃣️执行load方法
call_load_methods();
}
//prepare_load_methods 里会调用 schedule_class_load
static void schedule_class_load(Class cls)
{
if (cls->data()->flags & RW_LOADED) return;
// Ensure superclass-first ordering
//1⃣️沿着继承链递归调用,先加载父类
schedule_class_load(cls->superclass);
add_class_to_loadable_list(cls);
cls->setInfo(RW_LOADED);
}
void call_load_methods(**void**)
{
void *pool = objc_autoreleasePoolPush();
do {
while (loadable_classes_used > 0) {
//1⃣️先执行类的load方法
call_class_loads();
}
//2⃣️再执行分类的load方法
more_categories = call_category_loads();
// 3. Run more +loads if there are classes OR more untried categories
} while (loadable_classes_used > 0 || more_categories);
objc_autoreleasePoolPop(pool);
}
//调用load方法
static void call_class_loads(void)
{
// Call all +loads for the detached list.
for (i = 0; i < used; i++) {
Class cls = classes[i].cls;
load_method_t load_method = (load_method_t)classes[i].method;
//拿到IMP,直接发送消息
(*load_method)(cls, SEL_load);
}
}
二、initialize调用是类第一次发送消息时调用,可能会调用多次。分类->父类->子类。
void _class_initialize(Class cls)
{
Class supercls;
bool reallyInitialize = NO;
supercls = cls->superclass;
if (supercls && !supercls->isInitialized()) {
//沿着继承链调用父类
_class_initialize(supercls);
}
if (!cls->isInitialized() && !cls->isInitializing()) {
cls->setInitializing();
reallyInitialize = YES;
}
//如果类本身没调用过initialize方法,就会执行方法
if (reallyInitialize) {
callInitialize(cls);
//实际是走消息发送流程
//((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);
}
}
调用多次情况(父类被调用多次):
子类没有initialize方法,父类有initialize方法,子类发送消息时:
第一次调用:先调用父类的initialize方法,
第二次调用:调用自己的initialize方法,发现自己没有实现该方法,objc_msgSend发送流程会查找父类的方法,调用父类的initialize方法