OC中类的本质是一个结构体c++
NSObject类中存在一个Class类型的isa指针。 咱们在Xcode编写一个类继承于NSObject,在terminal使用 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xx.m -o xx.cpp
将.m文件转成.cpp文件,窥探NSObject的底层实现。缓存
咱们发现NSObject类最后转成了一个经过typedef struct objc_object NSObject
定义的结构体,这大抵就是NSObject的底层实现了。咱们在OC中定义的一个类就是一个C语言的结构体。iphone
定义一个Student继承自Person类,声明一个成员变量int No;
,依然使用上述命令将其转成cpp文件,窥探Student的底层实现。函数
其中student结构体中存在一个Person_IMPL
的结构体,这就是Student的父类。因为我在Person类中声明了一个成员变量age,因此下面是Person_IMPL
的结构体的定义。3d
而 Person中又存在一个NSObject_IMPL
结构体,这是由于Person继承于NSObject。关于NSObject_IMPL
在上面已经介绍过,不作赘述。上述关系能够经过下图来表示。指针
OC中的对象主要能够分为实例对象、类对象、元类对象三种。code
instance对象就是经过类alloc出来的。实例对象中存储着一个isa指针和一些成员变量cdn
每一个类有且只有一个类对象,class对象中存放着一个isa指针,一个superclass指针,类的属性信息,类的对象方法信息,类的协议方法信息,类的成员变量信息等,其本质是一个objc_class的结构体。对象
每一个类有且只有一个元类对象,元类对象的结构跟类对象是同样只不过用途不同。能够经过runtime的class_isMetaClass
来验证某个类是否是元类,其本质是一个objc_class的结构体。blog
上图咱们能够看出:
在对象分类的类对象和元类对象中已经描述过其中存放的数据,而且说明元类中存放着和类对象同样结构的数据。
上述是在.cpp文件中找到的类结构体的定义,可是在条件编译的时候已经明确指出,在ObjC2已经不可用了。因而在runtime源码中有这样一个新的定义。
这是一个c++的结构体,他继承自objc_object,objc_object中有一个isa的成员变量和一些方法。
因此objc_class中存在一个isa,superclass指针,以及方法的缓存和类信息数据(bits)。第一个方法class_rw_t *data()
中调用了bits的data()
函数,返回了一个class_rw_t类型的结构体。
其中存放有方法列表、属性列表、协议列表等,其中还有一个class_ro_t的结构体,里面存放了类的基本信息,包括实例的大小,类名等。
咱们知道了类的本质和结构,那么咱们能够本身定义一个结构体,里面有跟类同样的变量,将咱们的类转换成这个结构体,来验证class的结构。
使用MJ大大编写的MJClassInfo,定义两个类,Person(一个成员变量、一个属性、一个类方法、一个实例方法),Student(一个成员变量、一个类方法、一个实例方法,一个协议),将其转换成相应的结构体类型,这里面是mj_objc_class。
咱们能够看出定义的实例方法放在method中,属性放在properties中,成员变量在ro的ivars中...
在student中遵照了一个协议,协议放在类的协议列表中:
咱们能够看到protocols的count为1,而person没有遵照协议因此其protocols的count为0。
使用MJClassInfo中的Meta()
方法获取元类并调用元类结构体的data()
方法窥探元类的结构:
咱们能够看出metaclass的结构与class 的结构同样,只不过存储的数据不同。咱们定义的类方法存储在metaclass的method中。
一个NSObject* obj = [[NSObject alloc] init];
实例对象占多少内存空间?
答:因为NSObject实例对象就是C语言中的结构体,而这个结构体中仅有一个isa指针,因此其使用的内存空间就是一个指针的内存空间。系统为NSObject对象分配了16个字节的空间,可是在64位系统中实际使用的只有8个字节,32位系统中实际使用的是4个字节。
2.对象的isa指针指向哪里?
答:经过isa和superclass的图例能够看出实例对象的isa指针指向类对象,类对象的isa指针指向其元类对象,元类对象的isa指针你指向基类。而子类和父类的isa以及元类的isa指针皆指向元类的基类。