一、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/
网友评论