美文网首页OC底层原理
类和分类的加载

类和分类的加载

作者: 只写Bug程序猿 | 来源:发表于2020-02-27 15:39 被阅读0次
懒加载类和非懒加载类

类的加载 篇章里边 我们说了加载了类,分类,协议等等一些事情,注释我们可以看出来这里加载的是非懒加载的类.那么怎么区分懒加载类和非懒加载类呢

  1. 非懒加载类:实现了+(void)load()方法
  2. 懒加载类 : 没有实现+(void)load()方法,并且非懒加载类中没有任何的引用或者使用
    比如
//person中为实现+(void)load()方法
@implementation LGPerson
- (void)saySomething{
    NSLog(@"%s",__func__);
}
+ (void)sayNB{
    NSLog(@"%s",__func__);
}
@end

@interface LGStudent : LGPerson
@property (nonatomic, strong) LGTeacher *teacher;
@end
@implementation LGStudent
static LGTeacher * te;
//teacher为非懒加载
+(void)load
{
    NSLog(@"%s",__func__);
}
@end

此时studentperson都为非懒加载,因为student继承了person

  1. 非懒加载类加载
    是在read_images时加载的.那么懒加载类呢
void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)
{
//简化后的代码
// 1:第一次进来 - 开始创建表
    // gdb_objc_realized_classes : 所有类的表 - 包括实现的和没有实现的
    // allocatedClasses: 包含用objc_allocateClassPair分配的所有类(和元类)的表。(已分配)
    if (!doneOnce) {
           doneOnce = YES;
        // namedClasses
        // Preoptimized classes don't go in this table.
        // 4/3 is NXMapTable's load factor
        int namedClassesSize =
            (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
        gdb_objc_realized_classes =
            NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
        
        allocatedClasses = NXCreateHashTable(NXPtrPrototype, 0, nil);
    }
    
    // 2:类处理
    for (i = 0; i < count; i++) {
      Class cls = (Class)classlist[I];
      Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
    }
    
    // 3: 方法编号处理
    for (EACH_HEADER) {
        SEL *sels = _getObjc2SelectorRefs(hi, &count);
        UnfixedSelectors += count;
        for (i = 0; i < count; i++) {
          const char *name = sel_cname(sels[i]);
          sels[i] = sel_registerNameNoLock(name, isBundle);
        }
    }

    // 4: 协议处理
    for (EACH_HEADER) {
        extern objc_class OBJC_CLASS_$_Protocol;
        Class cls = (Class)&OBJC_CLASS_$_Protocol;
        NXMapTable *protocol_map = protocols();
        protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
        for (i = 0; i < count; i++) {
            readProtocol(protolist[i], cls, protocol_map,
                         isPreoptimized, isBundle);
        }
    }
    
    // 5: 非懒加载类处理
    for (EACH_HEADER) {
      classref_t *classlist =
          _getObjc2NonlazyClassList(hi, &count);
      addClassTableEntry(cls);
      realizeClassWithoutSwift(cls);
    }
    
    // 6: 待处理的类
    if (resolvedFutureClasses) {
        for (i = 0; i < resolvedFutureClassCount; i++) {
            Class cls = resolvedFutureClasses[I];
            if (cls->isSwiftStable()) {
                _objc_fatal("Swift class is not allowed to be future");
            }
            realizeClassWithoutSwift(cls);
            cls->setInstancesRequireRawIsa(false/*inherited*/);
        }
        free(resolvedFutureClasses);
    }
    
    // 7:分类处理
   for (EACH_HEADER) {
       category_t **catlist =
           _getObjc2CategoryList(hi, &count);
       bool hasClassProperties = hi->info()->hasCategoryClassProperties();
       for (i = 0; i < count; i++) {
           category_t *cat = catlist[I];
           Class cls = remapClass(cat->cls);
       }
   }
}
  1. 懒加载类 和 initialize方法调用
    我们在研究消息发送的时候忽略了一点
IMP lookUpImpOrForward(Class cls, SEL sel, id inst, 
                       bool initialize, bool cache, bool resolver)
{
    IMP imp = nil;
    bool triedResolver = NO;

    runtimeLock.assertUnlocked();

    // Optimistic cache lookup
    if (cache) {
        imp = cache_getImp(cls, sel);
        if (imp) return imp;
    }
    runtimeLock.lock();
    checkIsKnownClass(cls);

    if (!cls->isRealized()) {
//如果cls未加载调用下边代码
 // !!!!!!! 证明懒加载的类是在第一次发送消息的时候加载的
       cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
    }
//!!!!!!!!! 根据注释我们可以看出来 `initialize `方法也是在第一次发送消息的时候调用的
    if (initialize  &&  !cls->isInitialized()) {
        runtimeLock.unlock();
        _class_initialize (_class_getNonMetaClass(cls, inst));
        runtimeLock.lock();
        // If sel == initialize, _class_initialize will send +initialize and 
        // then the messenger will send +initialize again after this 
        // procedure finishes. Of course, if this is not being called 
        // from the messenger then it won't happen. 2778172
    }
}
分类的加载

1.0 初探 分类的本质
我们利用clang -rewrite-objc xxx.m -o xxx.cpp进行查看

image.png
他是一个结构体.那么我们在源码中搜索
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;
    // Fields below this point are not always present on disk.
    struct property_list_t *_classProperties;

    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }

    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};
1.1 懒加载类 + 懒加载分类

懒加载类是在第一次发消息时加载lookupImpOrForward方法,
lookupImpOrForward--->realizeClassMaybeSwiftAndLeaveLocked--->realizeClassMaybeSwiftMaybeRelock--->realizeClassWithoutSwift---->methodlizeClass。
然后class的data()中就已经存在懒加载的分类方法了。

1. 2非懒加载类 + 非懒加载分类

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

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

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

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

发送消息的时候就去读取 - realizeClassWithoutSwift - methodlizeClass
就是我的类要在消息发送的时候才有 - 但是我的分类提前了 - 需要加载 - read_images - addUnattachedCategoryForClass - 但是没有实现类 就会在下面 prepare_load_methods 实现 prepare_load_methods - realizeClassWithoutSwift 给你提前了实现类的信息 - unattachedCategoriesForClass

相关文章

  • iOS底层原理19:类和分类的加载

    前面已经探究了类的加载流程,类分为懒加载类和非懒加载类,他们有不同加载流程,下面来探究下分类的加载,以及分类和类搭...

  • iOS开发中 +load 和 +initialize特点

    + load方法 在程序启动时,会加载所有的类和分类,并调用所有类和分类的 + load方法 先加载父类,再加载子...

  • 类的加载(下)

    上篇文章我们了解了类的加载和分类的数据准备 这篇我们继续分析分类的加载时机以及是如何加载到类中的 当类加载时,进入...

  • 类和分类的加载

    懒加载类和非懒加载类 在 类的加载 篇章里边 我们说了加载了类,分类,协议等等一些事情,注释我们可以看出来这里加载...

  • OC底层原理探索—类的加载(3)

    上一篇我们探索了类的加载流程等一系列方法以及懒加载类和非懒加载类这节课我们来探索下分类的加载流程 分类的本质 首先...

  • 【Java】【反射】类加载的概述和分类

    类加载的概述和分类 类加载器的概述负责将.class文件加载到内存中,并为之生生成对应的class对象。 类加载器...

  • laod和initialize

    laod和initialize +load +load方法会在runtime加载类、分类时调用,每个类、分类的+l...

  • iOS 类方法load和类方法initialize区别

    类方法 load 在程序启动的时候会加载 所有的类 和 分类,并调用 所有类 和 分类 的 +load 方法(先加...

  • 反射

    类加载器:加载过程 加载,连接,初始化 分类: Bootstrap ClassLoader 根类加载器:核心类的加...

  • 【深入理解Java虚拟机 】类的加载器

    1. 类加载器的分类 JVM 自带的类加载器 根类加载器( BootStrap ) 拓展类加载器 ( Extens...

网友评论

    本文标题:类和分类的加载

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