美文网首页
OC底层原理(二):OC对象的分类

OC底层原理(二):OC对象的分类

作者: TheEnded | 来源:发表于2019-05-29 10:04 被阅读0次

    接上篇OC底层原理(一)
    平时自己都有学习一些底层原理,但是太过分散,也没有写过笔记,这次正好通过mj课程查漏补缺,也记录下来。

    这篇还有一道面试题,我们还是在最后解答

    问:对象的isa指针指向哪里?
    之前我们一直说对象,但是其实我们说的都是实例对象,也就是instance对象,在Objective-C中的对象,其实有三种:
    • instance对象(实例对象)
    • class对象(类对象)
    • meta-class对象(元类对象)
    1. instance对象
      instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象
    NSObjcet *object1 = [[NSObjcet alloc] init];
    NSObjcet *object2 = [[NSObjcet alloc] init];
    

    这是两个不同的实例对象,分别占据两块不同的内存。
    实例对象在内存中存储的信息包括

    • isa指针
    • 其他成员变量
    image.png
    1. class对象
      我们通过class方法或runtime方法得到一个class对象。class对象也就是类对象
    NSObjcet *object1 = [[NSObjcet alloc] init];
    NSObjcet *object2 = [[NSObjcet alloc] init];
    
    Class objectClass1 = [object1 class];
    Class objectClass2 = [object2 class];
    Class objectClass3 = [NSObject class];
    // runtime
    Class objectClass4 = object_getClass(object1);
    Class objectClass5 = object_getClass(object2);
    

    objectClass1~~ objectClass5都是类对象,他们是同一个类对象,每一个类在内存中有且只有一个class对象。
    class对象在内存中存储的信息主要包括

    • isa指针
    • superclass指针
    • 类的属性信息(@property),类的成员变量信息(ivar)类的对象方法信息(instance method),类的协议信息(protocol)
    image.png
    1. meta-class对象
      runtime方法object_getClass中传入类对象,得到的就是元类对象
    //runtime方法object_getClass中传入类对象,得到的就是元类对象
    Class objectMetaClass = object_getClass([NSObject class]);
    // 但是调用类对象的class方法时得到还是类对象,无论调用多少次都是类对象
    Class objectClass3 = [NSObject class];
    Class cls = [[NSObject class] class];
    

    PS:为什么上面调用class方法还是返回类对象,可以查看到其源码。

    + (Class)class {
        return self;
    }
    - (Class)class {
        return object_getClass(self);
    }
    //object_getClass方法实现,在其他文件中,一起贴过来了
    Class object_getClass(id obj)
    {
        if (obj) return obj->getIsa();
        else return Nil;
    }
    

    上面第一段代码中objectMetaClass是NSObject的meta-class对象(元类对象)
    每个类在内存中有且只有一个meta-class对象。
    meta-class对象和class对象的内存结构是一样的,但是用途不一样,在内存中存储的信息主要包括

    • isa指针
    • superclass指针
    • 类的类方法的信息(class method)
    image.png

    meta-class对象和class对象的内存结构是一样的,只是因为存储信息不一样,有的信息是空的,图中只是展示了主要信息。

    isa指针

    这里就要放这张图了


    image.png

    isa、superclass总结

    1. instance的isa指向class
    2. class的isa指向meta-class
    3. meta-class的isa指向基类的meta-class,基类的isa指向自己
    4. class的superclass指向父类的class,如果没有父类,superclass指针为nil
    5. meta-class的superclass指向父类的meta-class,基类的meta-class的superclass指向基类的class
    6. instance调用对象方法的轨迹,isa找到class,方法不存在,就通过superclass找父类
    7. class调用类方法的轨迹,isa找meta-class,方法不存在,就通过superclass找父类
    为了证明isa指针的指向是不是我们上面所说的那样,我们用代码来试一下。
    image.png

    通过断点log出来person对象的isa指针和personClass对象的地址来看,他们并不一样。为什么呢?实际上从苹果64位系统开始,isa还需要一次位运算才能得到真正所指向的真实地址,位运算可以在objc4源码中找到。

    //这里是简化后的内容,只取了我们需要的
    # if __arm64__
    #   define ISA_MASK        0x0000000ffffffff8ULL
    # elif __x86_64__
    #   define ISA_MASK        0x00007ffffffffff8ULL
    

    因为我们是在mac上进行所以应该是x86架构,我们进行一下运算


    image.png

    这里我们就能看到person实例对象的isa指针指向的地址0x001d800100001229进行位运算&0x00007ffffffffff8之后,得到的最终地址就是0x0000000100001228,和personClass这个类对象地址一致,也验证了我们的说法。

    然后我们再看一下personClass(类对象)的isa是不是指向personMetaClass(元类对象)

    但是我们发现类对象无法直接打印出来isa指针 image.png
    对于类对象,我们已经知道了它的结构并且结构里肯定是有isa指针这个成员,这里我们自己定义一个结构体强制转换一下,拿到这个isa指针
    image.png

    然后我们再看一下isa指针的地址


    image.png
    我们发现经过转换后取到personClass(类对象)的isa同样需要经过位运算得到personMetaClass(元类对上)的地址。
    验证完成
    面试题解答

    问:对象的isa指针指向哪里?
    答:instance对象的isa指针指向class对象,
    class对象的isa指针指向meta-class对象,
    meta-class对象的isa指针指向基类的meta-class对象,
    基类的meta-class的isa指针也指向自己。

    相关文章

      网友评论

          本文标题:OC底层原理(二):OC对象的分类

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