1.OC的本质是什么?
OC的对象和类是基于C/C++的结构体来实现的。OC的代码转换过程如下:
OC->C/C++ ->汇编语言 -> 机器语言。
2.如何查看OC的代码转成了C/C++的代码呢?
例如创建了一个工程,名字为OC-01,编写代码如下:
@interface Student : NSObject
@end
@implementation Student
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Student *stu = [[Student alloc] init];
}
return 0;
}
启动命令行,切换路径到main.m所在的文件下,如下图:

回车,进入文件夹后,输入如下的字符串:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
解释:
xcrun---表示xcode 执行
iphoneos -- 表示苹果手机平台
-arch arm64 -- 表示架构为arm64
-rewrite-objc -- 表示重写objc的代码
main.m -- 表示要转成C++的文件
-o --表示输出
main.cpp -- 表示转成的文件名称(格式为:名称.cpp)
回车之后,就可在main.m的文件夹下可以看到main.cpp:

点击查看即可。
3.OC对象如何在内存中布局?
首先查看OC的定义如下:
@interface NSObject {
Class isa;
}
而NSObject的底层实现如下:
struct NSObject_IMPL {
Class isa;
};
而Class的定义如下:
typedef struct objc_class *Class;
从而可以知道,isa是一个objc_class类型的结构体指针,而指针在64位系统中,占用8个字节,32位系统中,占用4个字节。
当一个对象alloc时,会自动分配内存空间,而对象的第一属性就是isa指针,所以,对象的内存就指向了第一个属性地址,即isa地址。
4.一个NSObject对象占用多少内存?
从第3个问题中,我们可能猜想一个NSObject对象的内存大概是8个字节,我们可以用class_getInstanceSize和malloc_size这两个函数来查看内存分配的大小。
首先,引入 #import <objc/runtime.h> 来调用class_getInstanceSize;
如下图:

用class_getInstanseSize这个方法得出的结果是8个字节;
但是,导入头文件:#import <malloc/malloc.h> 方便调用malloc_size()这个方法,如下图:

这个方法获取到的内存大小是16.
所以,内存到底是8还是16呢?
去查看class_getInstanceSize的底层代码如下:

查看alignedInstanceSize的源码如下:

官方解释,就是alignedInstanceSize这个方法返回的是一个类其成员变量所占用的内存大小。
总结如下:
一个NSObject对象,会分配16个字节的内存,但是占用的内存只有8个字节。
补充:
指针占用8个字节,基础数据类型占用4个字节,那么一个基于NSObject的对象,有一个字符串类型的name,一个int类型的age,那么属性占用的内存应该是:isa指针的内存+name指针的内存+age的内存 = 8+8+4 = 20,但是实际上是24。这是因为苹果底层采用的内存对其的方法,也就是说分配的内存永远是8的倍数,如果没有到8的倍数,就自动补齐。
如果此时,再添加一个int类型的height,那么其内存大小也是24.
疑问:
为什么NSObject对象内部只占用了8个字节,但是却分配了16个字节的空间呢?我们去查看创建内存的源码,如下:

点击查看instanceSize的源码如下:

官方解释就是,coreFoundation要求所有的object对象至少都要分配16个字节的内存。所以,虽然只占用了8个字节的内存,但是还是会分配16个字节。
来源:CSDN
作者:一人前行
链接:https://blog.csdn.net/lyz0925/article/details/103647292