返回
iOS对象的本质 & ISA
IOS
2023-10-30 18:30:35
了解了isa指针的存在,以及它是如何初始化的,我们来深究一下对象存在的本质。对象的本质归根结底是它的类型,这个类型在OC中指的是一个class。Class在底层编译器里是Class结构体。
这个结构体可以简单的总结为四种关键信息:
版本信息
:存储当前类的版本信息超类信息
:存储当前类的父类信息,本身也是一个Class结构体方法列表
:存储当前类的所有方法列表,以函数指针数组的形式呈现实例变量列表
:存储当前类所有成员变量信息,存储的格式是一个指针数组
举个例子来说,假设我们有一个Person
类,它的结构如下:
@interface Person : NSObject
{
NSString *name;
int age;
}
-(NSString *)name;
-(void)setName:(NSString *)name;
-(int)age;
-(void)setAge:(int)age;
@end
那么在编译的时候,Person
类会被转换成如下代码:
struct Person_IMPL {
Class isa;
NSString *name;
int age;
};
typedef struct Person_IMPL Person;
struct Person_class_t {
Class isa;
Class superclass;
Method list[4];
};
typedef struct Person_class_t Person_class;
Person_class *_OBJC_CLASS_Person;
可以看到,Person
类在编译后被翻译成了两个结构体,一个叫做Person_IMPL
,这是它的实现部分,存储了类的实例变量信息。另一个叫做Person_class
,这是类的部分,存储了类的版本信息、父类信息、以及方法列表。
而当我们在OC代码中,创建一个Person对象时,底层会发生以下一系列事情:
- 首先,编译器会去检查当前类有没有被注册,如果没有则会调用
_objc_registerClassPair
函数进行注册。 - 注册成功后,编译器会去分配内存空间,这个内存空间的大小是通过
class_getInstanceSize
函数计算出来的。 - 内存分配完成后,编译器会调用
objc_alloc
函数,这个函数的作用是将分配的内存空间和类信息绑定在一起。 - 最后,编译器会调用
objc_init
函数,这个函数的作用是调用类的初始化方法,对类的成员变量进行初始化。
完成以上四个步骤后,一个完整的Person对象就创建成功了。
上面说到objc_alloc
函数的作用是将分配的内存空间和类信息绑定在一起,那么这个绑定是怎么实现的呢?
其实,在分配内存空间的时候,编译器会在内存的第一个字节处存储一个指针,这个指针指向类的信息,也就是Person_class结构体。这个指针就叫做isa指针。
所以,当我们想要获取一个对象的类信息时,只需要通过isa指针就可以获取到。