在探索OC对象的本质之前,我们要明白Objective-C的代码,底层的实现都是C/C++代码。
而OC中的对象、类则是基于C/C++的结构体来实现的。
我们可以通过将创建好的OC文件,转化成C++文件来看一下OC对象的底层结构。
OC代码转换成C++
通过命令行将OC的main.m文件转换成C++,生成 main.cpp。
clang -rewrite-objc main.m -o main.cpp
/***rewrite代表 重写
*-o代表 输出
*cpp代表 c++(c plus plus)
**/
需要注意这种方式没有指定运行平台和架构模式,我们可以通过命令行设置参数,来指定运行平台和架构模式
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
/***xcrun代表 xcode
* iphoneos代表 运行在iPhone上
*-arch代表 架构模式,arm64参数代表64位的架构模式
**/
生成的main-arm64.cpp 文件就是main.m转换c++后的文件,直接拖拽到工程中,就可以查看底层实现了。我们在main-arm64.cpp 文件中搜索NSObjcet,可以找到NSObjcet_IMPL(IMPL即 implementation 的缩写,代表实现)。
struct NSObject_IMPL {
Class isa;
};
可以看到,NObject的底层实现就是一个结构体。我们进一步查看Class
typedef struct objc_class *Class;
我们发现Class其实就是一个指针,指向了objc_class类型的结构体。
OC对象内存空间
通过以上探索我们可以得出总结,OC中对象的底层实现都是通过C\C++的结构体实现的。那么一个OC对象占据了多少内存空间呢?下面让我们用代码实际验证一下。
通过代码我们创建了一个NSObject对象,分别调用了class_getInstanceSize
和malloc_size
方法来查看占据的内存空间。我们看到打印输出了8和16,这是怎么回事呢?
我们通过查看OC源码可知,class_getInstanceSize
是返回类的成员变量占据内存的大小。而malloc_size
是获取obj指针指向内存的大小
我们上文创建的NSObject对象obj的结构体只有一个成员:isa
指针,而指针在64位架构中占8个字节,所以第一次打印输出了8。但是系统为obj对象分配了16个字节的内存,第二次打印输出16。
上图中黄色区域系统为obj对象分配的16个字节的内存,但是obj对象结构体中只有一个isa指针,所以只占据了绿色区域的8个字节。这一点可以通过查看alloc底层源码也可以证实:
通过alloc
底层源码可以看到,如果一个对象占据的内存小于16时,则会直接返回16,也就是说,系统在为对象分配内存空间时,最小为16个字节。
至此我们知道了系统在创建一个对象的时