美文网首页
iOS Runtime中isa指针详解

iOS Runtime中isa指针详解

作者: 小盟城主 | 来源:发表于2018-11-29 15:56 被阅读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。
    

    相关文章

      网友评论

          本文标题:iOS Runtime中isa指针详解

          本文链接:https://www.haomeiwen.com/subject/jzwzqqtx.html