【OC底层原理学习笔记】1- OC对象的本质

发布时间 2023-06-08 15:55:28作者: hyq803

一、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/