iO Category加载流程2

103 阅读2分钟

「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战」。

这个地方又会牵扯到几种情况:分类的懒加载和非懒加载,类的懒加载和非懒加载。

区分懒加载和非懒加载,按苹果的意思就是实现了+load方法的类/分类是非懒加载,否则是懒加载
这就会产生4种情况,我们一种一种的来看。
老规矩,先创建个Person类,再创建个Person+HJJJJJ分类
分类添加2方法

-(void)sayYes;
-(void)sayNo;

1. 非懒加载类,非懒加载分类。

通过realizeClassWithoutSwift一直往后走 ,最终走到attachCategories,附加分类的东西。
在方法内部增加 断点,通过分类名字来断。

    const char *tempChar;
    tempChar = cls->nameForLogging();
    if (strcmp(tempChar, "Person")==0) {
        
    }
    /// 依次读取每一个category,将其methods,property,protocol添加到mlists,proplist,protolist中存储
    for (uint32_t i = 0; i < cats_count; i++) {
        auto& entry = cats_list[i];

        method_list_t *mlist = entry.cat->methodsForMeta(isMeta);
        //printf("22-%s\n",entry.cat->name);
        if (mlist) {
            
            if (strcmp(entry.cat->name, "HJJJJJ")==0) {
                
            }
            if (mcount == ATTACH_BUFSIZ) {
                prepareMethodLists(cls, mlists, mcount, NO, fromBundle);
                rw->methods.attachLists(mlists, mcount);
                mcount = 0;
            }
            mlists[ATTACH_BUFSIZ - ++mcount] = mlist;
            fromBundle |= entry.hi->isBundle();
        }

打印一下从分类里取出来的方法method_list_t *mlist = entry.cat->methodsForMeta(isMeta),元类取的是类方法,类取的是实例方法。\

image.png

我添加了2个实例方法,那么来看看isMeta为false,会发现从分类里取出的sayYes和sayNo方法, 而后会通过attachLists添加到rw的methods里。在之后打印rw的methods 看看

image.png

所以流程是map_images->_read_images->realizeClassWithoutSwift->methodizeClass->objc::unattachedCategories.attachToClass->attachCategories->rw->methods.attachLists

2. 非懒加载类,懒加载分类。

发现并没有走attachCategories,往前打断点,会发现methodizeClass方法里直接attachLists 到rw里了

  // Install methods and properties that the class implements itself.
    method_list_t *list = ro->baseMethods();
    if (list) {
        const char *tempChar;
        tempChar = cls->nameForLogging();
        if (strcmp(tempChar, "Person")==0) {
            
        }
        prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
        rw->methods.attachLists(&list, 1);
    }

打印结果:

image.png

流程是map_images->_read_images->realizeClassWithoutSwift->methodizeClass->rw->methods.attachLists

3. 懒加载类,非懒加载分类。

既然是懒加载的类,那么只有在用到的时候才会加载了,map_images则不会断住了,通过attachCategories里的断点,看看堆栈信息。

image.png

可以看到是在load_images里加载的,在调用load方法之前会做一些处理,prepare_load_methods里会对非懒加载类和非懒加载分类进行处理。
流程是load_images->prepare_load_methods->realizeClassWithoutSwift->methodizeClass->objc::unattachedCategories.attachToClass->attachCategories->rw->methods.attachLists

4. 懒加载类,懒加载分类

这种情况需要第一个发送消息时才会加载,在main方法[Person new]一下,看看断点的堆栈信息。\

image.png

流程是第一次发送消息,调用objc_msgSend->lookUpImpOrForward->realizeClassWithoutSwift->methodizeClass->rw->methods.attachLists