笔记02

作者: fearless123 | 来源:发表于2020-04-14 18:14 被阅读0次

    Category的用途:

    1.类的拆解:根据不同功能将代码放入不同分类中(模拟多继承),减少单个类的体积;
    2.公开“私有方法”(私有方法前向引用):类扩展中已声明私有方法,去分类.h声明;

    • (a) 类扩展中声明私有方法
    @interface Person ()
    // 类扩展声明的私有方法
    - (void)ExtensionPrivateMethod ;
    @end
    
    @implementation Person
    - (void)ExtensionPrivateMethod {
        NSLog(@"类扩展@interface()有声明,私有方法");
    }
    @end
    
    • (b) 分类.h再次声明
    #import "Person.h"
    @interface Person (Category1)
    // .h中声明私有方法,.m中无需实现
    - (void)ExtensionPrivateMethod;
    @end
    
    #import "Person+Category1.h"
    @implementation Person (Category1)
    @end
    
    • (c) 调用私有方法,需要引入类和分类
    #import "Person.h"
    #import "Person+Category1.h"
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Person *person = [[Person alloc] init];
            // 私有方法前向引用
            [person ExtensionPrivateMethod];
        }
        return 0;
    }
    

    总结:
    1.如果不在分类.h中公开私有方法,可以通过performSelector方式强制调用私有方法或者拿到它的函数指针调用
    2.正常的方式调用就需要在分类.h中公开(声明)私有方法,不实现

    Person *person = [[Person alloc] init];
    [person performSelector:@selector(ExtensionPrivateMethod)];
    

    Category结构

    分类不能直接添加成员变量,因为category中没有存储成员变量对应的指针变量;
    可以利用关联对象技术实现为category添加成员变量的效果;
    分类能添加属性,但是不会生成setter和getter方法;

    struct category_t {
        const char *name;                           // 分类的名称
        classref_t cls;                             // 分类所属的列
        struct method_list_t *instanceMethods;      // 添加的实例方法列表
        struct method_list_t *classMethods;         // 添加的类方法列表
        struct protocol_list_t *protocols;          // 添加的协议列表
        struct property_list_t *instanceProperties; // 添加的实例属性列表
        struct property_list_t *_classProperties;   // 类属性(class, nonatomic, strong)
    }
    
    • 关联对象技术实现为分类添加成员变量
    #import "Person+Category.h"
    #import <objc/runtime.h> // 类相关函数
    //#import <objc/message.h> // 消息相关函数
    
    @implementation Person (Category)
    
    // 关联对象 能够为分类添加属性
    - (void)setName:(NSString *)name {
        objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN);
    }
    
    - (NSString *)name {
        return objc_getAssociatedObject(self, @"name");
    }
    
    @end
    

    关联对象API
    设置类关联属性 void _object_set_associative_reference(object, key, value, policy)
    获取类关联属性 id _object_get_associative_reference(object, key);
    移除类所有关联属性 void _object_remove_assocations(object);

    • 设置类关联属性 _object_set_associative_reference(object, key, value, policy)
    /**
    @param object 准备被关联的对象
    @param key 要关联的值对应的key 标识
    @param value 关联的值
    @param policy 策略
     */
    void _object_set_associative_reference(id object, void *key, id value,  uintptr_t policy) {
        // 存放 policy 和 关联值value 默认为空
        ObjcAssociation old_association(0, nil);
                                               
        // 根据 策略policy 对 value 进行加工,按照策略对value进行 copy或者retain
        // newValue ---> 准备关联的值
        id new_value = value ? acquireValue(value, policy) : nil;
      
        {
            // 关联对象管理类,C++实现一个类  
            // 维护了一个单例Hash表 AssociationsHashMap对象
            AssociationsManager manager;
            
            /**
             初始化一个 AssociationsHashMap 对象 associations
             用来维护对象 和 ObjectAssociationMap 之间的关系
             单例对象 AssociationsHashMap
             */
            AssociationsHashMap &associations(manager.associations());
            
            // 获取关联对象的索引 ---> DISGUISE 对这个指针地址 按位取反
            disguised_ptr_t disguised_object = DISGUISE(object);
    
            if (new_value) {
                // 根据对象指针查找对应的一个ObjectAssociateMap结构的map
                AssociationsHashMap::iterator i = associations.find(disguised_object);
                
                // 从全局容器中找到了ObjectAssociationMap
                if (i != associations.end()) {
                    // secondary table exists  -->  i->second
                    // i->first 表示对象指针
                    // i->second 表示获取 ObjectAssociationMap
                    ObjectAssociationMap *refs = i->second;
                    // 根据传递进来的key进行查找
                    ObjectAssociationMap::iterator j = refs->find(key);
    
                    if (j != refs->end()) { // ObjcAssociation 找到了
                        old_association = j->second;
                        // 如果关联对象已存在,则通过ObjcAssociation赋新值(替换最新的value)
                        j->second = ObjcAssociation(policy, new_value);
                    } else {
                        // 如果关联对象不存在,则创建新的关联对象
                        (*refs)[key] = ObjcAssociation(policy, new_value);
                    }
                } else {
                    /**
                     create the new association (first time).
                     如果没有 ObjectAssociationMap 表
                     则第一次创建一个 ObjectAssociationMap 表
                     */
                    ObjectAssociationMap *refs = new ObjectAssociationMap;
                    // 全局容器中的key = disguised_object
                    // 全局容器中的value = 这个新创建的map
                    associations[disguised_object] = refs;
                    /**
                    新关联的值 new_value 通过策略 policy 组装成 ObjcAssociation 
                    作为新创建好的map, ObjectAssociationMap[key]
                    key 传进来的key
                    */
                    (*refs)[key] = ObjcAssociation(policy, new_value);
                    // 最后设置这个对象是有关联对象
                    object->setHasAssociatedObjects();
                }
            } else {
                /**
                 如果new_value为 空,那么删除该关联对象
                 */
                AssociationsHashMap::iterator i = associations.find(disguised_object);
                // 查找到了这个ObjectAssociationMap
                if (i !=  associations.end()) {
                    ObjectAssociationMap *refs = i->second;
                    // 通过key 到 ObjectAssociationMap中查找
                    ObjectAssociationMap::iterator j = refs->find(key);
                    if (j != refs->end()) {
                        // 找到了ObjcAssociation
                        old_association = j->second;
                        // 擦除操作,从ObjectAssociationMap中移除
                        // 所以我们想移除关联对象,可以将关联对象的值设置为nil进行移除
                        refs->erase(j);
                    }
                }
            }
        }
        // 释放旧值
        if (old_association.hasValue()) ReleaseValue()(old_association);
    }
    
    • 获取类关联属性 _object_get_associative_reference(object, key)
    // 用来得到已有的关联对象
    id _object_get_associative_reference(id object, void *key) {
        id value = nil;
        uintptr_t policy = OBJC_ASSOCIATION_ASSIGN;
        {
            // 初始化AssociationsManager
            AssociationsManager manager;
            /**
             初始化一个AssociationsHashMap 对象 associations
             用来维护对象和ObjectAssociationMap之间的关系
             */
            AssociationsHashMap &associations(manager.associations());
            // 获取关联对象的索引
            disguised_ptr_t disguised_object = DISGUISE(object);
            // 根据对象指针查找对应的一个ObjectAssociateMap结构的map
            // 通过迭代器 找到对应的 ObjectAssociationMap
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            
            if (i != associations.end()) {
                // i->first 表示对象地址
                // i->second表示获取ObjectAssociationMap
                ObjectAssociationMap *refs = i->second;
                // 通过find(key)找到ObjectAssociationMap
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    // 获取到ObjcAssociation
                    ObjcAssociation &entry = j->second;
                    // 取值 取出value和policy
                    value = entry.value();
                    policy = entry.policy();
                    if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) {
                        objc_retain(value);
                    }
                }
            }
        }
        if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) {
            objc_autorelease(value);
        }
        return value;
    }
    
    • 移除类所有关联对象 _object_remove_assocations(object)
    void _object_remove_assocations(id object) {
        vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
        {
            AssociationsManager manager;
            AssociationsHashMap &associations(manager.associations());
            if (associations.size() == 0) return;
            disguised_ptr_t disguised_object = DISGUISE(object);
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i != associations.end()) {
                // 找到ObjectAssociationMap 开始遍历
                // 拷贝所有需要删除的关联对象
                ObjectAssociationMap *refs = i->second;
                for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
                    elements.push_back(j->second);
                }
                // 删除 ObjectAssociationMap
                delete refs;
                associations.erase(i);
            }
        }
        // 将拷贝的值再次遍历release.
        for_each(elements.begin(), elements.end(), ReleaseValue());
    }
    
    

    Category的加载过程

    • _objc_init() runtime入口函数,进行一些初始化操作
    void _objc_init(void) {
        static bool initialized = false;
        if (initialized) return;
        initialized = true;
        
        environ_init();
        tls_init();
        static_init();
        lock_init();
        exception_init();
    
        // 注册了三个回调函数
        _dyld_objc_notify_register(&map_images, load_images, unmap_image);
    }
    
    • map_images() 加锁
    void map_images(unsigned count, const char * const paths[],
               const struct mach_header * const mhdrs[]) {
        // 加锁
        rwlock_writer_t lock(runtimeLock);
        // 完成所有类的注册 和 fixup 等操作,还包括一些初始化工作以及 调用load类方法
        return map_images_nolock(count, paths, mhdrs);
    }
    
    • map_images_nolock() 完成所有类的注册和fixup等工作,还包括一些初始化工作以及调用load类方法
    void  map_images_nolock(unsigned mhCount, const char * const mhPaths[],
                      const struct mach_header * const mhdrs[]) {
        ......
        ......
    
        /**
        _read_images 完成两件事
        1、将category和类绑定在一起
        2、重建类的方法列表
         */
        if (hCount > 0) {
            // 完成类的加载,协议的加载,类别的加载等工作
            _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
        }
        firstTime = NO;
    }
    
    • _read_images() 完成类、协议、分类的加载等工作

    _read_images()中主要完成了两件事情
    1、addUnattachedCategoryForClass(...) 将category和类绑定在一起
    2、remethodizeClass(...)重建类的方法列表

    void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses) {
        ......
       // 发现分类
       for (EACH_HEADER) {
            // 从编译好的文件获取所有的分类
            category_t **catlist = _getObjc2CategoryList(hi, &count);
            bool hasClassProperties = hi->info()->hasCategoryClassProperties();
            
            // 遍历category列表
            for (i = 0; i < count; i++) {
                category_t *cat = catlist[I];
                // 重映射分类所属的类
                Class cls = remapClass(cat->cls);
    
                if (!cls) {
                    catlist[i] = nil;
                    continue;
                }
    
                bool classExists = NO;
                if (cat->instanceMethods ||  
                    cat->protocols  ||  
                    cat->instanceProperties)  {
                    // 绑定分类和目标类 or 将category添加到分类表中
                    addUnattachedCategoryForClass(cat, cls, hi);
                    // 判断类是否初始化
                    if (cls->isRealized()) {
                        // 重新构建方法列表
                        remethodizeClass(cls);
                        classExists = YES;
                    }
                }
    
                // 把category的类方法和协议添加到类的metaclass上(元类)
                if (cat->classMethods  ||
                    cat->protocols  ||  
                    (hasClassProperties && cat->_classProperties))  {
                    addUnattachedCategoryForClass(cat, cls->ISA(), hi);
                    if (cls->ISA()->isRealized()) {
                        remethodizeClass(cls->ISA());
                    }
                }
            }
        }
        if (DebugNonFragileIvars) {
            realizeAllClasses();
        }
    }
    
    // 将category添加到分类表中
    static void addUnattachedCategoryForClass(category_t *cat, Class cls, 
                                              header_info *catHeader) {
        runtimeLock.assertWriting();
        // 获取未处理的分类的表(没有把分类中的信息添加到类中去)
        // NXMapTable 是哈希表
        NXMapTable *cats = unattachedCategories();
        category_list *list;
    
        // 根据类获取对应的分类数组
        list = (category_list *)NXMapGet(cats, cls);
        if (!list) {
            list = (category_list *)
                calloc(sizeof(*list) + sizeof(list->list[0]), 1);
        } else {
            // 扩容
            list = (category_list *)
                realloc(list, sizeof(*list) + sizeof(list->list[0]) * (list->count + 1));
        }
        // 把当前分类添加到分类数组中 list中是一系列locstamp_category_t
        list->list[list->count++] = (locstamped_category_t){cat, catHeader};
        // 把新的list插入到分类表中去 key=cls, value=list
        NXMapInsert(cats, cls, list);
    }
    
    
    • remethodizeClass() 重建类的方法列表
    // 重建类的方法列表
    static void remethodizeClass(Class cls) {
        category_list *cats;
        bool isMeta;
        runtimeLock.assertWriting();
        // 是否是元类
        isMeta = cls->isMetaClass();
        // 获取类对应的分类数组,并且从分类的哈希表中删除掉分类数组
        if ((cats = unattachedCategoriesForClass(cls, false/*not realizing*/))) {
            // 将分类的method、protocol、property添加到class中
            attachCategories(cls, cats, true /*flush caches*/);        
            // 释放分类
            free(cats);
        }
    }
    
    // 获取cls中未完成整合的所有分类
    static category_list *unattachedCategoriesForClass(Class cls, bool realizing) {
        runtimeLock.assertWriting();
        // 返回对应的分类
        return (category_list *)NXMapRemove(unattachedCategories(), cls);
    }
    
    • attachCategories() 将分类中的方法和属性列表绑定到目标类上

    attachCategories 主要是创建一个新的方法列表空间,存放category中的实例方法、类方法、协议方法,然后将这个方法列表交给attachLists处理

    static void attachCategories(Class cls, category_list *cats, bool flush_caches) {
        // 对分类进行空判断,如果没有直接return
        if (!cats) return;
        // 判断是否是元类
        bool isMeta = cls->isMetaClass();
        /**
         方法列表 二维数组
         [
            [method_t, method_t],
            [method_t],
            [method_t, method_t,method_t],
            ...
         ]
         */
        // 方法列表
        method_list_t **mlists = (method_list_t **)
            malloc(cats->count * sizeof(*mlists));
        // 属性列表
        property_list_t **proplists = (property_list_t **)
            malloc(cats->count * sizeof(*proplists));
        // 协议列表
        protocol_list_t **protolists = (protocol_list_t **)
            malloc(cats->count * sizeof(*protolists));
    
        int mcount = 0;
        int propcount = 0;
        int protocount = 0;
        
        // 原有类的分类的总数
        int i = cats->count;
        bool fromBundle = NO;
        
        // 遍历所有分类,依次将每个分类里面的方法添加到临时的数组中
        // 后编译的分类会先调用  
        while (i--) { // 倒序遍历,最先访问最后编译的分类
           
            // 获取该分类的方法列表
            auto& entry = cats->list[I];
            // 返回类的方法列表,并拼接在临时的方法数组中
            method_list_t *mlist = entry.cat->methodsForMeta(isMeta);        
            if (mlist) {
                mlists[mcount++] = mlist;
                fromBundle |= entry.hi->isBundle();
            }
    
            // 属性列表添加规则 同方法列表添加规则
            property_list_t *proplist = 
                entry.cat->propertiesForMeta(isMeta, entry.hi);
            if (proplist) {
                proplists[propcount++] = proplist;
            }
    
            // 协议列表添加规则 同方法列表添加规则
            protocol_list_t *protolist = entry.cat->protocols;
            if (protolist) {
                protolists[protocount++] = protolist;
            }
        }
    
        // 获取宿主类当中的 rw 数据,其中包含宿主类的方法列表信息
        auto rw = cls->data();
    
        // 主要是针对 分类中关于内存管理相关方法情况下的 一些特殊处理
        prepareMethodLists(cls, mlists, mcount, NO, fromBundle);
    
        /**
         rw 代表类
         methods 代表类的方法列表
         attachLists 方法的含义是 将含有mcount个元素的mlists拼接到 rw 的methods上
         */
    
        // 1、创建新的 方法列表 和 目标类中方法列表融合
        // 1、把分类中的方法添加class中的方法列表中去
        rw->methods.attachLists(mlists, mcount);
        free(mlists);
    
        if (flush_caches  &&  mcount > 0) flushCaches(cls);
        // 2、创建新的 属性列表 和 目标类的属性列表融合
        // 2、把分类中的属性添加class中的属性列表中去
        rw->properties.attachLists(proplists, propcount);
        free(proplists);
    
        // 3、创建新的 协议列表 和 目标类的协议列表融合
        // 3、将分类中的协议列表添加到class中的协议列表中去
        rw->protocols.attachLists(protolists, protocount);
        free(protolists);
    }
    
    
    • attachLists() 将类中的方法和分类中的方法放到一个列表中

    oldCount:目标类中方法列表长度
    addedCount:category方法列表的长度
    mommove:将类方法后移addedCount个偏移量
    momcpy:将category中方法复制到偏移量从0到addedCount的类方法列表中
    所以category中的方法并没有覆盖类中的方法,只是将category中的方法放到了类方法的前面,调用方法的时候,如果category和类中有同名方法,系统会找到前面category中的方法返回并调用。category中的方法优先级高于类中的方法

    void attachLists(List* const * addedLists, uint32_t addedCount) {
        if (addedCount == 0) return;
        
        // 有数组的情况下
        if (hasArray()) {
            // many lists -> many lists
            // 列表中原有元素总数 oldCount
            uint32_t oldCount = array()->count;
    
            // 拼接之后的元素总数
            uint32_t newCount = oldCount + addedCount;
    
            // 根据新总数重新分配内存
            setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
    
            // 重新设置元素总数
            array()->count = newCount;
            /**
             内存移动
             [[], [], [], [原有的第一个元素], [原有的第二个元素]]
             */
            memmove(array()->lists + addedCount,
                    array()->lists,
                    oldCount * sizeof(array()->lists[0]));
            
            /**
             内存拷贝
             [
                A ---> [addedLists中的第一个元素]
                B ---> [addedLists中第二个元素]
                C ---> [addedLists中第三个元素]
                [原有的第一个元素]
                [原有的第二个元素]
             ]
             */
            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;
    
            // 将类方法直接移动到列表的addedCount位置
            if (oldList) array()->lists[addedCount] = oldList;
            // 将Category中的方法拷贝到array数组中位置从0~addedCount-1前面
            memcpy(array()->lists, addedLists,
                   addedCount * sizeof(array()->lists[0]));
        }
    }
    

    总结:通过Runtime加载某个类的所有category数据,将所有category的方法、属性、协议信息合并到一个大数组中,后参与编译的category数据,会在数组的前面(后编译先调用while(--)),将合并后的category数据(方法、属性、协议)插入到类原来数据的前面

    Category的"覆盖"问题

    后编译的category中的同名方法会覆盖前面编译的category中的同名方法
    category覆盖类中的同名方法
    可以通过函数指针调用原有类中的方法

    #import "Person.h"
    #import "Person+Category1.h"
    #import "Person+Category2.h"
    #import <objc/runtime.h>
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
      
            Person *person = [[Person alloc] init];
            [person test];
    
            // 调用person中的test方法
            unsigned int count = 0;
            Method *methodList = class_copyMethodList([Person class], &count);
            
            IMP imp = NULL;
            SEL sel = NULL;
            for (unsigned int i = 0; i < count; i ++) {
                Method method = methodList[i];
                SEL methodSEL = method_getName(method);
                NSString *methodName = [NSString stringWithUTF8String:sel_getName(methodSEL)];
                if ([methodName isEqualToString:@"test"]) {
                    imp = method_getImplementation(method);
                    sel = method_getName(method);
                }
            }
            ((void(*)(id, SEL))(void *)imp)(person, sel);
            free(methodList);
        }
        return 0;
    }
    
    
    函数指针调用

    load方法加载顺序

    load_images中主要做了2件事情:
    1、发现load方法 prepare_load_methods();
    2、调用load方法 call_load_methods();

    void load_images(const char *path __unused, const struct mach_header *mh) {
        // 判断是否有load方法,没有load方法直接返回
        if (!hasLoadMethods((const headerType *)mh)) return;
    
        // 递归锁
        recursive_mutex_locker_t lock(loadMethodLock);
    
        // Discover load methods 发现load方法
        {
            // 读写锁
            rwlock_writer_t lock2(runtimeLock);
            // 发现load方法
            prepare_load_methods((const headerType *)mh);
        }
    
        // Call +load methods (without runtimeLock - re-entrant)
        // 调用load方法
        call_load_methods();
    }
    
    • prepare_load_methods()

    prepare_load_methods()中schedule_class_load(isa->superclass) 通过递归先将父类中的load方法存入loadable_class,所有得出父类的load优先于子类的load方法调用

    void prepare_load_methods(const headerType *mhdr) {
        size_t count, i;
        runtimeLock.assertWriting();
    
        // 获取非懒加载的类的列表
        classref_t *classlist =  _getObjc2NonlazyClassList(mhdr, &count);
            for (i = 0; i < count; i++) {
            // 核心1:【获得子类和父类中所有的load方法】load 方法如何别处理在这里 先加载父类 再加载子类
            schedule_class_load(remapClass(classlist[i]));
        }
    
        // 获得非懒加载category的列表 分类没有父类
        category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
        for (i = 0; i < count; i++) {
            category_t *cat = categorylist[i];
            // 重映射获取分类所属的类
            Class cls = remapClass(cat->cls);
            if (!cls) continue;  // category for ignored weak-linked class 忽略弱连接的分类
            // 初始化类信息
            realizeClass(cls);
            assert(cls->ISA()->isRealized());
            // 核心2:添加到loadable_categories
            add_category_to_loadable_list(cat);
        }
    }
    
    static void schedule_class_load(Class cls) {
        // 判断是否为空
        if (!cls) return;
        assert(cls->isRealized());  // _read_images should realize
        
        /**
         // load方法已经被执行过
         #define RW_LOADED             (1<<23)
         和下面的 cls->setInfo(RW_LOADED)  对应
         */
        // 判断是否已经添加过load方法到load方法列表中
        if (cls->data()->flags & RW_LOADED) return;
    
        // 通过递归找到父类的load方法并添加,实际上调用自身的方法
        schedule_class_load(cls->superclass);
    
        // 将Class和IMP添加到调用列表中
        add_class_to_loadable_list(cls);
        // 设置class状态为已经添加过load方法 意思是设置了一个标志
        cls->setInfo(RW_LOADED); 
    }
    
    • call_load_methods() load方法的调用

    通过do-while循环中 call_class_loads()和 call_category_load()可以看出,优先调用类的load方法,再调用分类的调用方法
    load方法通过函数指针调用

    void call_load_methods(void) {
        static bool loading = NO;
        bool more_categories;
    
        loadMethodLock.assertLocked();
    
        // Re-entrant calls do nothing; the outermost call will finish the job.
        if (loading) return;
        loading = YES;
    
        void *pool = objc_autoreleasePoolPush();
    
        do {
            // 1. Repeatedly call class +loads until there aren't any more
            while (loadable_classes_used > 0) {
                // 1.先调用类中的+load方法
                call_class_loads();
            }
    
            // 2. Call category +loads ONCE
            // 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);
    
        loading = NO;
    }
    
    // 调用类的load方法
    static void call_class_loads(void) {
        int i;
        
        // Detach current loadable list.
        // 获取当前loadable_classes列表
        struct loadable_class *classes = loadable_classes;
        int used = loadable_classes_used;
        loadable_classes = nil;
        loadable_classes_allocated = 0;
        loadable_classes_used = 0;
        
        // Call all +loads for the detached list.
        
        // 从子类到父类,遍历所有类中的 +load 方法
        // 遍历loadable_classes列表,依次执行load方法,只遍历已添加的load方法的列表元素used
        for (i = 0; i < used; i++) {
            Class cls = classes[i].cls;
            load_method_t load_method = (load_method_t)classes[i].method;
            // 如果cls为空,则不执行其load方法
            if (!cls) continue; 
    
            // 通过函数地址直接调用load方法
            (*load_method)(cls, SEL_load);
        }
        
        // Destroy the detached list.
        if (classes) free(classes);
    }
    
    

    相关文章

      网友评论

        本文标题:笔记02

        本文链接:https://www.haomeiwen.com/subject/ylrtvhtx.html