Objective-C
Objective-C是C语言的超集,我们平时写得OC,底层的实现都是C\C++代码,OC的对象、类是基于C\C++的结构体实现的。
可以使用以下命令行将OC代码转换为C\C++代码(只能作为参考不一定百分百准确)
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -o <输出的.cpp文件>
如果需要链接其他框架,使用- framework参数,比如-framework UIKit
NSObject
一般我们写的对象都继承于NSObject,所以弄清楚NSObject相当关键
- NSObject底层实现相关源码
struct NSObject_IMPL{
Class *isa
}
//Class是objc_class结构体指针
typedef objc_class *Class
NSObject类里只有Class isa指针,所以obj对象的地址值就是isa指针的地址值。表面上看之只占用了8个字节(指针变量8个字节),阅读OC源码可以看到实质是分配了16个字节。
可以使用以下API查看内存使用情况
//一个实例对象至少需要多少字节
class_getInstanceSize([NSObject class]);
//一个实例对象实际占用多少字节
malloc_size((__brige const void *)obj);
一个继承NSObject的类的结构体
//例如
@interface Person : NSObject
@property (nonatomic, assign) int age;
@end
struct Person_IMPL{
stuct NSObject_IMPL NSObject_IVARS;
int _age;
}
//NSObject_IMPL的成员变量只有isa指针一个,所以实际结构体等价如下,person实例对象的地址值还是isa指针的地址值,再继承也同理
struct Person_IMPL{
Class *isa;
int _age;
}
OC对象分类
OC对象分为三类:instance对象(实例对象)、class对象(类对象)、meta-class对象(元类对象)
- instance对象:通过类alloc出来的对象,每次alloc都会创建新的实例对象
NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
//obj1、obj2都是instance对象,它们是不同的两个对象,分别占据着不同的内存
instance对象在内存中存储的信息有isa指针和其他成员变量。
- class对象(类对象)
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = object_getClass(object1);
Class objectClass4 = object_getClass(object2);
Class objectClass5 = [NSObject class];
objectClass1 ~ objectClass5都是NSObject的class对象
它们都是同一个对象,每一个类在内存中有且只有一个class对象
class对象在内存中存储的信息主要包括:
isa指针
superclass指针
类的属性信息(@property)、类的对象方法信息(instance method)
类的协议信息(protocol)、类的成员变量信息(ivar)
- meta-class(元类对象)
//获取元类对象的方法
Class objMetaClass = object_getClass([NSObject class]);
/*
注意:这个方法获取到的还是类对象
Class objMetaClass = [[NSObject class] class];
*/
objectMetaClass是NSObject的meta-class对象(元类对象)
每个类在内存中有且只有一个meta-class对象
meta-class对象和class对象的内存结构是一样的,只是用途不一样而已,在内存中存储的信息主要包括:
isa指针
superClass指针
类的类方法信息
......
- Class的结构
//struct objc_class 结构
struct objc_class{
Class isa;
Class superclass;
Cache_t cache;//方法缓存
class_data_bit_t bit;//用于获取类的具体信息
}
// bit & FAST_DATA_MASK 得到类的具体信息
struct class_rw_t { // rw表示可读写
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods; //method_t 二维数组
property_array_t properties; //属性二维数组
protocol_array_t protocols; //协议二维数组
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
}
//struct class_ro_t 的结构
struct class_ro_t { //ro表示只读
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#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指针和supclass指针
- instance的isa指针指向class
instance调用对象方法时,通过isa指针找到class,找出对应的对象方法进行调用 - class的isa指针指向meta-class
调用类方法时,通过class的isa找到meta-class,找出对应的类方法进行调用
从Arm64开始,优化了isa指针,isa & ISA_MASK才是真正的地址值
- class对象的superclass指针指向父类class对象
当instance调用父类对象方法时,先通过isa指针找到class,再通过class对象的superclass指针找到父类,然后再找出对应对象方法进行调用 -
meta-class对象的superclass指针指向父类的meta-class对象
调用父类类方法时,通过class的isa找到meta-class,再通过meta-class对象的superclass指针找到父类,然后再找出对应的类方法进行调用