要认识什么是isa指针,我们得先明确一点:
在Objective-C中,任何类的定义都是对象。类和类的实例(对象)没有任何本质上的区别。任何对象都有isa指针。
那么什么是类呢?在xcode中用快捷键Shift+Cmd+O 打开文件objc.h 能看到类的定义:
可以看到:Class 是一个 objc_class 结构类型的指针, id是一个 objc_object 结构类型的指针。
isa指针
isa指针是一个指向对象所属类或元类的指针。它决定了对象可以调用的方法和属性。isa指针在对象的结构中存在,并且在运行时会被自动设置。
在Objective-C中,每个对象都有一个isa指针,它指向该对象所属的类或元类。isa指针决定了对象可以调用的方法和属性。通过isa指针,Objective-C运行时可以在运行时动态地确定对象所属的类,并在该类或其父类中查找对应的方法实现。
下面是一些示例代码来说明isa指针的作用:
@interface MyClass : NSObject
- (void)myMethod;
@end
@implementation MyClass
- (void)myMethod {
NSLog(@"MyClass's myMethod");
}
@end
int main() {
MyClass *myObject = [[MyClass alloc] init];
[myObject myMethod];
return 0;
}
在上面的示例中,创建了一个名为MyClass的类,它继承自NSObject。MyClass类中定义了一个名为myMethod的方法。
当我们创建一个MyClass对象并调用myMethod方法时,实际上发生了以下过程:
- 分配内存并初始化MyClass对象。
- 运行时为该对象设置isa指针,使其指向MyClass的类对象。
- 在myObject上调用myMethod方法时,运行时首先通过isa指针找到MyClass的类对象。
- 运行时在类对象中查找名为myMethod的方法实现并执行。
通过这个过程,我们可以看到isa指针在动态确定对象所属的类的过程中起到了关键作用。它使得我们可以在运行时根据对象的实际类型来调用适当的方法。
每一个对象本质上都是一个类的实例。其中类定义了成员变量和成员方法的列表。对象通过对象的isa指针指向类。
每一个类本质上都是一个对象,类其实是元类(metaClass)的实例。元类定义了类方法的列表。类通过类的isa指针指向元类。
所有的元类最终继承一个根元类,根元类isa指针指向本身,形成一个封闭的内循环。
每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向metaClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是: 元类(metaClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root metaClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。
实例如下:
@interface Dog : NSObject{
NSInteger _age;
NSString *name;
}
- (void)pengta;
+ (void)hehe;
@end
@implementation Dog
- (void)pengta{
printf("instance dog");
}
+ (void)hehe{
printf("class dog");
}
@end
所有Dog的实例的isa都指向了Dog(Class)。
Dog(Class)是一个全局变量,其中记录了类名、成员变量信息、property信息、protocol信息和实例方法列表等。
Dog(Class)的isa指向了全局变量Dog(meta-class),meta-class里只记录了类名、类方法列表等。
Dog *dog = [[Dog alloc] init];
[dog pengta];
向Dog (instance) 发送消息pengta时,运行时会通过isa指针查找到Dog(Class),这里保存着本类中定义的实例方法的指针。
[Dog hehe];
向Dog(Class)发送消息hehe时,运行时会通过isa查找到Dog(meta-class),这里保存着本类中定义的类方法的指针。
Meta Class(元类)
所有的类自身也是一个对象,我们可以向这个对象发送消息(即调用类方法)。如:
NSArray *array = [NSArray array];
这个例子中,+array消息发送给了NSArray类,而这个NSArray也是一个对象。既然是对象,那么它也是一个objc_object指针,它包含一个指向其类的一个isa指针,这个isa指针也要指向这个类所属的类。那么这些就有一个问题了,这个isa指针指向什么呢?这就引出了meta-class的概念:
meta-class是一个类对象的类
当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta-class的方法列表中查找。
meta-class 是必须的,因为它为一个 Class 存储类方法。每个Class都必须有一个唯一的 meta-class,因为每个Class的类方法基本不可能完全相同。
再深入一下,meta-class也是一个类,也可以向它发送一个消息,那么它的isa又是指向什么呢?为了不让这种结构无限延伸下去,Objective-C的设计者让所有的meta-class的isa指向基类的meta-class,以此作为它们的所属类。即,任何NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己的所属类 (在一定程度上可以理解为若一个Class继承自NSObject,则这个Class的meta-class继承自NSObject的meta-class),而基类的meta-class的isa指针是指向它自己,这就是说 NSObject 的 meta-class 的 isa 指针指向NSObject 的 meta-class自己。这样就形成了一个完美的闭环。