iOS Runtime中isa指针详解
一、Runtime中数据结构
Runtime 又叫运行时,是一套底层的 C 语言 API,是 iOS 系统的核心之一。开发者在编码过程中,可以给任意一个对象发送消息,在编译阶段只是确定了要向接收者发送这条消息,而接受者将要如何响应和处理这条消息,那就要看运行时来决定了。
C语言中,在编译期,函数的调用就会决定调用哪个函数。
而OC的函数,属于动态调用过程,在编译期并不能决定真正调用哪个函数,只有在真正运行时才会根据函数的名称找到对应的函数来调用。
Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。
OC代码被编译器转化为C语言,然后再通过运行时执行,最终实现了动态调用。这其中的OC类、对象和方法等都对应了C中的结构体,而且我们都可以在Rutime源码中找到它们的定义。
Runtime的头文件的引用为
#import <objc/runtime.h>
在Objective-C中,任何类的定义都是对象。类和类的实例(对象)没有任何本质上的区别。任何对象都有isa指针。
isa:是类指针,之所以说isa是指针是因为Class其实是一个指向objc_class结构体的指针,而isa 是它唯一的私有成员变量,即所有对象都有isa指针(isa位置在成员变量第一个位置)
那么什么是类呢?在xcode中用快捷键shift+command+o
打开文件objc.h 能看到类的定义:
objc.h
#if !OBJC_TYPES_DEFINED
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
#endif
可以看出:
Class 是一个 objc_class 结构类型的指针, id是一个 objc_object 结构类型的指针。
1. id ---> objc_object
///A pointer to an instance of a class.
typedef struct objc_object *id;
通过A pointer to an instance of a class.可以了解到我们创建的一个对象或实例其实就是一个objc_object结构体,而我们常用的id也就是这个结构体的指针。
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
objc_object结构体中可以看出来,这个结构体只有一个成员变量,这是一个Class类型的变量isa。
我们都知道id在OC中是表示一个任意类型的类实例,从这里也可以看出,OC中的对象虽然没有明显的使用指针,但是在OC代码被编译转化为C之后,每个OC对象其实都是拥有一个isa的指针的。
2. Class ---> objc_class
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
Class是一个指向objc_class结构体的指针,那么objc_class又是什么呢?
在<objc/runtime.h>中我们看到:
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;//这个就是上面说的 每个对象都有isa指针 在结构体指针中第一个成员变量的位置上
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE; /*父类*/
const char * _Nonnull name OBJC2_UNAVAILABLE; /*类名*/
long version OBJC2_UNAVAILABLE; /*版本信息*/
long info OBJC2_UNAVAILABLE; /*类信息*/
long instance_size OBJC2_UNAVAILABLE; /*实例大小*/
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE; /*实例参数链表*/
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE; /*方法链表*/
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE; /*方法缓存*/
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE; /*协议链表*/
#endif
} OBJC2_UNAVAILABLE;
该结构体的第一个成员变量也是isa指针,这就说明了Class本身其实也是一个对象
可以看出objc_class是个结构体,而且第一个成员变量也是isa指针,这个指针指向的Class不是指向自己而是metaclass(元类)
那么metaclass(元类)是什么呢?
每个实例对象也就是struct objc_object结构体它的isa的指针指向类对象Class,而Class里也有个isa的指针, 指向metaClass(元类)。元类是类对象的类,类对象是元类的实例。
这时候相对于元类,objc_class就是元类的实例对象。基于这种设计模式,不难发现:
- 我们以前调用 "+" 开头的类方法实际是在调用元类的对象方法,元类保存了类方法的列表和成员变量
- 由于每个类有且只有一个,所以每个类对象都是其对应元类的单例
- 元类(metaClass)也是类,它也是对象。
- 元类也有isa指针,它的isa指针最终指向的是一个根元类(root metaClass)
- 根元类的isa指针指向本身,这样形成了一个封闭的内循环。
各个类实例变量的继承关系:
关系图
1. objc_object中的isa指的是对象的类。
2. objc_class中的isa指的是类的元类。
3. superClass是一层层集成的,到最后NSObject的superClass是nil。而NSObject的isa指向根元类,这个根元类的isa指向它自己,而它的superClass是NSObject,也就是最后形成一个环。
4. metaClass也是相互继承的。
5. 从objc_class结构体可以看出来,里面有个isa属性,还有个super_class属性,它俩都是指针,其实在objc_class的定义中也能看出来,每一个objc_class都有isa,但是不一定会有super_class。