ObjC中的类和实例对象

NSObject

OC中类的本质是一个结构体c++

NSObject

NSObject类中存在一个Class类型的isa指针。 咱们在Xcode编写一个类继承于NSObject,在terminal使用 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xx.m -o xx.cpp 将.m文件转成.cpp文件,窥探NSObject的底层实现。缓存

NSObject的底层实现

咱们发现NSObject类最后转成了一个经过typedef struct objc_object NSObject定义的结构体,这大抵就是NSObject的底层实现了。咱们在OC中定义的一个类就是一个C语言的结构体。iphone

有继承关系的类

定义一个Student继承自Person类,声明一个成员变量int No;,依然使用上述命令将其转成cpp文件,窥探Student的底层实现。函数

Student

Student底层实现

其中student结构体中存在一个Person_IMPL的结构体,这就是Student的父类。因为我在Person类中声明了一个成员变量age,因此下面是Person_IMPL的结构体的定义。3d

`Person_IMPL`的结构体

而 Person中又存在一个NSObject_IMPL结构体,这是由于Person继承于NSObject。关于NSObject_IMPL在上面已经介绍过,不作赘述。上述关系能够经过下图来表示。指针

继承关系

ObjC对象的分类

OC中的对象主要能够分为实例对象、类对象、元类对象三种。code

  • instance对象(实例对象)

instance对象就是经过类alloc出来的。实例对象中存储着一个isa指针和一些成员变量cdn

  • class对象 (类对象)

每一个类有且只有一个类对象,class对象中存放着一个isa指针,一个superclass指针,类的属性信息,类的对象方法信息,类的协议方法信息,类的成员变量信息等,其本质是一个objc_class的结构体。对象

  • meta-class对象 (元类对象)

每一个类有且只有一个元类对象,元类对象的结构跟类对象是同样只不过用途不同。能够经过runtime的class_isMetaClass来验证某个类是否是元类,其本质是一个objc_class的结构体。blog

isa和superclass

isa和superclass

上图咱们能够看出:

  • instance的isa指针指向class,class的isa指针指向meta-class,metaclass的isa指针指向root-class
  • subclass的superclass指针指向superclass,依次直到root-class,root-class的superclass指针为nil。meta-class的superclass指针指向其superclass的meta-class,依次到root-class,root-class的superclass指向rootclass的class。
  • 而subclass和superclass的isa以及meta-class的isa指针皆指向meta-class的root-class。
  • instance调用实例方法的轨迹:经过isa找class,找不到就经过superclass找父类。
  • class调用类对象的轨迹:经过isa找meta-class,找不到就经过superclass找父类。

Class对象分析

在对象分类的类对象和元类对象中已经描述过其中存放的数据,而且说明元类中存放着和类对象同样结构的数据。

ObjC2之前的类信息

上述是在.cpp文件中找到的类结构体的定义,可是在条件编译的时候已经明确指出,在ObjC2已经不可用了。因而在runtime源码中有这样一个新的定义。

新的ObjC定义

这是一个c++的结构体,他继承自objc_object,objc_object中有一个isa的成员变量和一些方法。

objc_object

因此objc_class中存在一个isa,superclass指针,以及方法的缓存和类信息数据(bits)。第一个方法class_rw_t *data()中调用了bits的data()函数,返回了一个class_rw_t类型的结构体。

class_rw_t结构体

其中存放有方法列表、属性列表、协议列表等,其中还有一个class_ro_t的结构体,里面存放了类的基本信息,包括实例的大小,类名等。

class_ro_t

验证class

咱们知道了类的本质和结构,那么咱们能够本身定义一个结构体,里面有跟类同样的变量,将咱们的类转换成这个结构体,来验证class的结构。

使用MJ大大编写的MJClassInfo,定义两个类,Person(一个成员变量、一个属性、一个类方法、一个实例方法),Student(一个成员变量、一个类方法、一个实例方法,一个协议),将其转换成相应的结构体类型,这里面是mj_objc_class。

窥探class

Person类对象信息

咱们能够看出定义的实例方法放在method中,属性放在properties中,成员变量在ro的ivars中...

在student中遵照了一个协议,协议放在类的协议列表中:

student类对象

咱们能够看到protocols的count为1,而person没有遵照协议因此其protocols的count为0。

使用MJClassInfo中的Meta()方法获取元类并调用元类结构体的data()方法窥探元类的结构:

meta-class结构

咱们能够看出metaclass的结构与class 的结构同样,只不过存储的数据不同。咱们定义的类方法存储在metaclass的method中。

两个问题

  1. 一个NSObject* obj = [[NSObject alloc] init];实例对象占多少内存空间?

    答:因为NSObject实例对象就是C语言中的结构体,而这个结构体中仅有一个isa指针,因此其使用的内存空间就是一个指针的内存空间。系统为NSObject对象分配了16个字节的空间,可是在64位系统中实际使用的只有8个字节,32位系统中实际使用的是4个字节。

2.对象的isa指针指向哪里?

答:经过isa和superclass的图例能够看出实例对象的isa指针指向类对象,类对象的isa指针指向其元类对象,元类对象的isa指针你指向基类。而子类和父类的isa以及元类的isa指针皆指向元类的基类。

相关文章
相关标签/搜索