iOS Runtime中isa指针详解

2018-11-29  本文已影响1539人  小盟城主

一、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

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就是元类的实例对象。

基于这种设计模式,不难发现:

  1. 我们以前调用 "+" 开头的类方法实际是在调用元类的对象方法,元类保存了类方法的列表和成员变量
  2. 由于每个类有且只有一个,所以每个类对象都是其对应元类的单例
  3. 元类(metaClass)也是类,它也是对象。
  4. 元类也有isa指针,它的isa指针最终指向的是一个根元类(root metaClass)
  5. 根元类的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。
上一篇下一篇

猜你喜欢

热点阅读