load和initialize方法

240 阅读1分钟

一、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方法