iOS---11---类和分类加载

[toc]

image.png

类的加载

非懒加载类在运行时处理,懒加载编译期确定.
区分:方式为load方法,把所有类的加载提前.
看代码, _getObjc2NonlazyClassList 是读取非懒加载类列表

image.png

只打印LGTeacher,但是LGPerson未打印,在LGTeacher实现了+(void)load方法.

懒加载 类

编译期已经确定

创建LGPerson,不实现load方法,调用alloc创建一个实例

 LGPerson *object = [LGPerson alloc];

因为方法的调用都会来到lookUpImpOrForward方法类,打下断点,发现走进如下的代码中,cls->isRealized()类没有初始化,所以为false,

 if (!cls->isRealized()) {
        cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
        // runtimeLock may have been dropped but is now locked again
    }

代码跟进,发现走到realizeClassMaybeSwiftMaybeRelock这个方法
if 为oc使用,下面是swif才会走
realizeClassWithoutSwift这个方法对类进行初始化,rw ro处理等等

 if (!cls->isSwiftStable_ButAllowLegacyForNow()) {
        // Non-Swift class. Realize it now with the lock still held.
        // fixme wrong in the future for objc subclasses of swift classes
        realizeClassWithoutSwift(cls);
        if (!leaveLocked) lock.unlock();
    } else {
        // Swift class. We need to drop locks and call the Swift
        // runtime to initialize it.
        lock.unlock();
        cls = realizeSwiftClass(cls);
        assert(cls->isRealized());    // callback must have provoked realization
        if (leaveLocked) lock.lock();
    }

懒加载类 在第一次发送消息的进行处理.

分类的加载

懒加载类 + 懒加载分类

LGPersonLGPerson+test中,load方法全部注释掉,在read_images里面,

image.png

发现打印结果没有LGPerson名字

image.png

LGPerson调用alloc方法,来到lookuporforward发现,
这个流程和懒加载类一样

这个流程和上面的3流程相似,就是入口不是read_images,而是lookupImpOrForward方法,
lookupImpOrForward--->realizeClassMaybeSwiftAndLeaveLocked--->realizeClassMaybeSwiftMaybeRelock--->realizeClassWithoutSwift---->methodlizeClass。
然后class的data()中就已经存在懒加载的分类方法了。

懒加载类 + 非懒加载类

LGPerson+test中,实现load方法,在realizeClassWithoutSwift打下断点,查看函数调用栈

image.png

查看流程,我们发现调用了load_imageprepare_load_methods方法,虽然LGTeaher类是懒加载,但是分类实现了load方法,所以从dyld调用加载到内存. 而load_image,我们在dyldobjc`的方法中有见过.

prepare_load_methods方法中

image.png

首先,这个方法是将非懒加载类取出来,并且遍历将load方法加入到add_class_to_loadable_list中,但是LGTeaher为懒加载类所以不会走

classref_t *classlist = 
        _getObjc2NonlazyClassList(mhdr, &count);
    for (i = 0; i < count; i++) {
        schedule_class_load(remapClass(classlist[i]));
        
    }

接下来调用realizeClassWithoutSwift将类的实现加到内存,紧接着,调用方法add_category_to_loadable_list()将分类load加入数组中.

image.png

在懒加载类 + 非懒加载分类这种情况下,分类方法是在load_images() -> prepare_load_methods() -> realizeClass() -> methodizeClass() -> attachCategories()中将分类方法添加到类的rw.methods中的。attachCategories()的实现就不全贴出来了,其中有一行代码:

image.png

总结:
实现load 方法的时候

  • 懒加载的类 + 非懒加载的分类 - 类似 - 子类实现了 - 父类 伴随这一期实现
  • 发送消息的时候就去读取 - realizeClassWithoutSwift - methodlizeClass
  • 就是我的类要在消息发送的时候才有 - 但是我的分类提前了 - 需要加载 - read_images - addUnattachedCategoryForClass - 但是没有实现类 就会在下面 prepare_load_methods 实现
  • prepare_load_methods - realizeClassWithoutSwift 给你提前了实现类的信息 -unattachedCategoriesForClass

非懒加载类 + 懒加载分类

因为class为非懒加载,所以会直接会走正常的class的加载初始化流程:read_images---->realizeClassWithoutSwift---->methodlizeClass
初始化完成后,classro中就已经存在懒加载的分类方法了。这里编译器已经自动的将category方法加进去了;

read_image里面,打下断点,发现分类的方法也已经在

image.png

read_images - realizeClassWithoutSwift - methodlizeClass - 不需要添加表 - 直接在相应data() - ro

非懒加载类 + 非懒加载分类

主类和分类都实现load方法.接下来会发生什么?
methodizeClass打断点发现cats为NULL

image.png

methodizeClass在打印查看只有类的load方法,并没有分类的load方法

在methodizeClass,中有句代码

// Attach categories.
    category_list *cats = unattachedCategoriesForClass(cls, true /*realizing*/);
    attachCategories(cls, cats, false /*don't flush caches*/);

点进去查看

attachCategories


    auto rw = cls->data();

    prepareMethodLists(cls, mlists, mcount, NO, fromBundle);
    rw->methods.attachLists(mlists, mcount);

attachLists

void attachLists(List* const * addedLists, uint32_t addedCount) {
        if (addedCount == 0) return;

        if (hasArray()) {
            // many lists -> many lists
            uint32_t oldCount = array()->count;//10
            uint32_t newCount = oldCount + addedCount;//4
            setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
            array()->count = newCount;// 10+4
   
            memmove(array()->lists + addedCount, array()->lists,
                    oldCount * sizeof(array()->lists[0]));
            
            memcpy(array()->lists, addedLists, 
                   addedCount * sizeof(array()->lists[0]));
        }
        else if (!list  &&  addedCount == 1) {
            // 0 lists -> 1 list
            list = addedLists[0];
        } 
        else {
            // 1 list -> many lists
            List* oldList = list;
            uint32_t oldCount = oldList ? 1 : 0;
            uint32_t newCount = oldCount + addedCount;
            setArray((array_t *)malloc(array_t::byteSize(newCount)));
            array()->count = newCount;
            if (oldList) array()->lists[addedCount] = oldList;
            memcpy(array()->lists, addedLists, 
                   addedCount * sizeof(array()->lists[0]));
        }
    }

完成对非懒加载分类的加载

因为class为非懒加载,所以首先会加载初始化class;然后因为分类也是非懒加载的,所以会调用_read_images中的分类相关的加载初始化,在此过程中调用了下面绑定分类到class的方法:
addUnattachedCategoryForClass
这样在_read_images过程中完成了分类的attach

图解

小技巧 注意点

image.png

未注册的类可以写入ivar
但是如果2 和 3 调换位置 无法添加
在这一步已经返回 无法写入
注册之后ro已经不能修改
未注册之前 ro还可以写入 ivarro
但是可以操作rw

image.png

添加属性 要实现setget方法 使用setvalue 底层调用set方法
动态类 创建添加 解耦合

类和分类加载图示

image.png

你可能感兴趣的:(iOS---11---类和分类加载)