前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS——Objective-C 对象的结构分析

iOS——Objective-C 对象的结构分析

作者头像
CC老师
发布2022-03-15 08:06:09
3930
发布2022-03-15 08:06:09
举报

通过分析对象的本质得知实例对象的isa指向类对象,那类对象的isa呢,我们接下来就对 isa 的流程进行分析。

一、 lldb 探索isa

定义一个 SHPerson 对象,在 main 函数初始化并断点调试。

lldb打印结果如下:

  • 第一次打印是person的内存分布,并且 0x000021a1000080e9(isa) & 0x0000000ffffffff8ULL,得到person的isa指向的内存地址为0x00000001000080e8且名为SHPerson的class对象。
  • 第二次打印是class对象的内存分布,并且 0x00000001000080c0(isa) & 0x0000000ffffffff8ULL,得到的内存地址为 0x00000001000080c0,po打印的结果是名为SHPerson的calss对象。
  • 对比第一次第二次的打印,两个分别为0x00000001000080e8和0x00000001000080c0的内存地址,打印的出来的class对象的名称是一样的。
  • 第三次是打印0x00000001000080c0的内存分布,并且 0x00000001003790f0(isa) & 0x0000000ffffffff8ULL,得到的内存地址为 0x00000001003790f0,po打印的结果是名为NSObject的calss对象。
  • 再对比前两次的打印,发现是不一样的,0x00000001003790f0和0x00000001000080e8、0x00000001000080c0打印出来的class对象名称是不一样的。
  • 第四次是打印0x00000001003790f0的内存分布,这次发现拿到的 isa 竟然和它一样本身一样,说明0x00000001003790f0的isa指向的是它自己本身。

接下来,将对这三个内存地址进行研究:

0x00000001000080e8
0x00000001000080c0
0x00000001003790f0

当然,这个内存地址是可能会变的,具体需要自己根据断点进行lldb打印。

二、烂苹果(MachOView)查看符号表,推导出类对象,元类对象,根元类对象。

使用MachOView打开代码的可执行文件(exec)。

找到符号表,并且滚动到黄褐色的部分。

发现,00000001000080E8,

00000001000080C0的内存地址不就是上面提到要研究的么,再根据value这一列的值,就可以得知,0x00000001000080e8是类对象,

0x00000001000080c0是元类对象,那么0x00000001003790f0是什么?

0x00000001003790f0是一个叫根元类对象的东西。

总结如下:

实例对象的isa指向类对象,类对象的isa指向元类对象,元类对象的isa指向根元类对象,根元类对象的isa指向的是自己本身。

三、类对象,元类对象,根元类对象的继承链

类对象,元类对象,根元类对象是否也有继承链呢?如果有,是怎么样的一个继承链呢?添加一个继承至SHPerson的SHStudent类。

并且为了方便理解,下面暂时先把SHStudent比作子类(subClass),SHPerson比作父类(superClass),NSObject比作根类(rootClass)。

1. runtime部分API介绍。

导入 #import <objc/runtime.h>

  • object_getClass: 传一个对象,返回这个对象的类对象。
  • class_getSuperclass: 传一个类,返回类的父类。
  • objc_getClass: 传一个类名称,返回对应的类对象。
  • objc_getMetaClass: 传一个类名称,返回对应的元类对象。

objc_getClass和objc_getMetaClass先作为了解,因为object_getClass就可以拿到类对象,元类对象,根元类对象,并且,更多runtime的API官方文档都有介绍。以下探索主要用到object_getClass和class_getSuperclass。

2. 使用 runtime API 打印输出

//1. 子类的instance对象isa流程和继承链。
NSLog(@"子类(SHStudent)打印");
     SHStudent *student = [[SHStudent alloc] init];
// class对象
     Class class_student = object_getClass(student);
// metaclass对象
     Class metaclass_student = object_getClass(class_student);
// rootMetaclass对象
     Class rootMetaclass_student = object_getClass(metaclass_student);

NSLog(@"class_student        : %@ - %p",class_student, class_student);
NSLog(@"metaclass_student    : %@ - %p",metaclass_student, metaclass_student);
NSLog(@"rootMetaclass_student: %@ - %p",rootMetaclass_student, rootMetaclass_student);

NSLog(@"------------------");

// class对象的superclass对象
     Class superclass_student = class_getSuperclass(class_student);
// metaclass对象的superclass对象
     Class superMetaclass_student = class_getSuperclass(metaclass_student);
// rootMetaclass对象的superclass对象
     Class superRootMetaclass_student = class_getSuperclass(rootMetaclass_student);

NSLog(@"superclass_student        : %@ - %p",superclass_student, superclass_student);
NSLog(@"superMetaclass_student    : %@ - %p",superMetaclass_student, superMetaclass_student);
NSLog(@"superRootMetaclass_student: %@ - %p",superRootMetaclass_student, superRootMetaclass_student);

//2. 父类的instance对象isa流程和继承链。
NSLog(@"");
NSLog(@"父类(SHPerson)打印");
     SHPerson *person = [[SHPerson alloc] init];
// class对象
     Class class_person = object_getClass(person);
// metaclass对象
     Class metaclass_person = object_getClass(class_person);
// rootMetaclass对象
     Class rootMetaclass_person = object_getClass(metaclass_person);

NSLog(@"class_person        : %@ - %p",class_person, class_person);
NSLog(@"metaclass_person    : %@ - %p",metaclass_person, metaclass_person);
NSLog(@"rootMetaclass_person: %@ - %p",rootMetaclass_person, rootMetaclass_person);

NSLog(@"------------------");

// class对象的superclass对象
     Class superclass_person = class_getSuperclass(class_person);
// metaclass对象的superclass对象
     Class superMetaclass_person = class_getSuperclass(metaclass_person);
// rootMetaclass对象的superclass对象
     Class superRootMetaclass_person = class_getSuperclass(rootMetaclass_person);

NSLog(@"superclass_person        : %@ - %p",superclass_person, superclass_person);
NSLog(@"superMetaclass_person    : %@ - %p",superMetaclass_person, superMetaclass_person);
NSLog(@"superRootMetaclass_person: %@ - %p",superRootMetaclass_person, superRootMetaclass_person);

//3. 根类的instance对象isa流程和继承链。
NSLog(@"");
NSLog(@"根类(NSObject)打印");
NSObject *object = [[NSObject alloc] init];
// class对象
     Class class_object = object_getClass(object);
// metaclass对象
     Class metaclass_object = object_getClass(class_object);
// rootMetaclass对象
     Class rootMetaclass_object = object_getClass(metaclass_object);

NSLog(@"class_object        : %@ - %p",class_object, class_object);
NSLog(@"metaclass_object    : %@ - %p",metaclass_object, metaclass_object);
NSLog(@"rootMetaclass_object: %@ - %p",rootMetaclass_object, rootMetaclass_object);

NSLog(@"------------------");

// class对象的superclass对象
     Class superclass_object = class_getSuperclass(class_object);
// metaclass对象的superclass对象
     Class superMetaclass_object = class_getSuperclass(metaclass_object);
// rootMetaclass对象的superclass对象
     Class superRootMetaclass_object = class_getSuperclass(rootMetaclass_object);

NSLog(@"superclass_object        : %@ - %p",superclass_object, superclass_object);
NSLog(@"superMetaclass_object    : %@ - %p",superMetaclass_object, superMetaclass_object);
NSLog(@"superRootMetaclass_object: %@ - %p",superRootMetaclass_object, superRootMetaclass_object);

(滑动显示更多)

3. lldb打印分析

红色箭头代表类对象的继承链,黄色箭头代表元类对象的继承链,绿色箭头代表根元类对象的继承链。

从图得知:

  1. 子类的类对象的父类,是父类的类对象,父类的类对象的父类,是根类的类对象,根类的类对象为nil。
  2. 子类的元类对象的父类,是父类的元类对象,父类的元类对象的父类,是根类的元类对象,根类的元类对象的父类,是根类的类对象。

结合下面的一张很经典的图,就更清楚了。

这种是一张广为流传并且很经典的图,这张图描述isa的流程以及class的继承链,通过以上的分析再来看这种图就有种豁然开朗的感觉,以前总看不懂这张。

其实不管是子类、父类、根类isa的流程和类的继承链都基本是一样的,真正的不同在于根元类对象(rootMetaclass)这个地方,isa的流程到这儿,isa指针再怎么指都是根元类对象自己,并且根元类对象的父类是根类,而根类对象的父类是一个nil。

原文链接:https://juejin.cn/post/7038460181121859597

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-01-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HelloCoder全栈小集 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、 lldb 探索isa
  • 二、烂苹果(MachOView)查看符号表,推导出类对象,元类对象,根元类对象。
  • 三、类对象,元类对象,根元类对象的继承链
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档