一、OC的本质
我们平时编写的Objective-C代码,底层实现其实都是C\C++代码
所以Objective-C的面向对象都是基于C\C++的数据结构实现的
Objective-C的对象、类主要是基于C\C++的结构体实现的
如何将Objective-C代码转换为C\C++代码?
在终端输入:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的cpp文件
例如:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
二、一个NSObject对象占用多少内存?
系统分配了16个字节给NSObject对象(通过malloc_size函数获得系统实际分配的内存大小)
但NSObject对象内部只使用了8个字节的空间(64位环境下,可以通过class_getInstanceSize函数获得)
NSObject *obj = [[NSObject alloc] init]; // 获得NSObject实例对象的成员变量所占用的大小:8 NSLog(@"%zd", class_getInstanceSize([NSObject class])); // 获得obj指针所指向内存的大小:16 NSLog(@"%zd", malloc_Size((__bridge const void *)obj)); // C++代码,内部只有一个成员变量isa指针,所以只占用8字节 struct NSObject_IMPL { Class isa; }; // runtime底层源码,size最小为16 size_t instanceSize(size_t extraBytes) { size_t size = alignedInstanceSize() + extraBytes; // CF requires all objects be at least 16 bytes. if (size < 16) size = 16; return size; }
三、一个Person对象、一个Student对象占用多少内存空间?
@interface Person : NSObject { int _age; } @interface Student : Person { int _no; } // C++代码 struct NSObject_IMPL { Class isa; }; struct Person_IMPL { struct NSObject_IMPL NSObject_IVARS; // 8 int _age; // 4 }; // 16 内存对齐:结构体的大小必须是最大成员大小的倍数 struct Student_IMPL { struct Person_IMPL Person_IVARS; // 16,有4个字节是空的正好给_no使用 int _no; // 4 }; // 16 // runtime底层源码,size最小为16 size_t instanceSize(size_t extraBytes) { size_t size = alignedInstanceSize() + extraBytes; // CF requires all objects be at least 16 bytes. if (size < 16) size = 16; return size; }
1、一个Person对象占用16个字节:isa占用8个字节,_age占用4个字节,8 + 4 < 16,所以取16
2、一个Student对象占用16个字节:isa占用8个字节,父类的_age占用4个字节,_no占用4个字节,8 + 4 + 4 = 16字节
3、内存对齐
计算结构体的大小的内存对齐:结构体的大小必须是最大成员大小的倍数
系统分配内存的内存对齐方式:16的倍数
四、OC对象
OC对象有instance对象(实例对象)、class对象(类对象)、meta-class对象(元类对象),class对象、meta-class对象的本质结构都是struct objc_class
//instance对象(实例对象) NSObject *object1 = [[NSObject alloc] init]; NSObject *object2 = [[NSObject alloc] init]; //class对象(类对象) //class方法返回的一直是class对象(类对象) Class objectClass1 = [object1 class]; Class objectClass2 = [object2 class]; Class objectClass3 = object_getClass(object1); Class objectClass4 = object_getClass(object2); Class objectClass5 = [NSObject class]; //meta-class对象(元类对象) //将类对象当做参数传入,获得元类对象 Class metaClass = object_getClass(objectClass5); NSLog(@"metaClass - %p", metaClass);
1、instance对象(实例对象)
instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象
instance对象在内存中存储的信息包括:
(1)isa指针
(2)其他成员变量
2、class对象(类对象)
每个类在内存中有且只有一个class对象
类对象在内存中存储的信息主要包括:
(1)isa指针
(2)superclass指针
(3)类的属性信息(@property)、类的对象方法信息(instance method)
(4)类的协议信息(protocol)、类的成员变量信息(ivar)
3、meta-class对象(元类对象)
每个类在内存中有且只有一个meta-class对象
meta-class对象和class对象的内存结构是一样的,但是用途不一样
在内存中存储的信息主要包括:
(1)isa指针
(2)superclass指针
(3)类的类方法信息(class method)
五、从源码查看struct objc_class结构
struct objc_class { Class isa; Class superclass; cache_t cache; // 方法缓存 class_data_bits_t bits; // 用于获取具体的类信息 }; // bits & FAST_DATA_MASK struct class_rw_t { uint32_t flags; uint32_t version; const class_ro_t *ro; method_list_t * methods; // 方法列表 property_list_t *properties; // 属性列表 const protocol_list_t * protocols; // 协议列表 Class firstSubclass; Class nextSiblingClass; char *demangledName; }; struct class_ro_t { uint32_t flags; uint32_t instanceStart; uint32_t instanceSize; // instance对象占用的内存空间 #ifdef __LP64__ uint32_t reserved; #endif const uint8_t * ivarLayout; const char * name; // 类名 method_list_t * baseMethodList; protocol_list_t * baseProtocols; const ivar_list_t * ivars; // 成员变量列表 const uint8_t * weakIvarLayout; property_list_t *baseProperties; };
六、对象的isa指针和superclass指针指向哪里?
1、isa指针
instance对象的isa指针指向class对象
class对象的isa指针指向meta-class对象
meta-class对象的isa指针指向基类的meta-class对象
2、superclass指针
class对象的superclass指针指向父类的class对象
如果没有父类,superclass指针为nil
meta-class对象的superclass指针指向父类的meta-class对象
基类的meta-class的superclass指针指向基类的class对象
苹果源码:opensource.apple.com/tarballs
objc4源码下载:https://opensource.apple.com/tarballs/objc4/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了