runtime之理解“类”

OC是一门动态运行时的语言,为了能够高效运作,不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。对runtime机制的理解,除了能深入了解系统的核心内容以外,也可以在项目中更好的去扩展以更高效的实现。

OC并不能直接编译为汇编语言,而是要先转写为纯C语言再进行编译和汇编的操作,从OC到C语言的过渡就是由runtime来实现的。然而我们使用OC进行面向对象开发,而C语言更多的是面向过程开发,这就需要将面向对象的类转变为面向过程的结构体。

因此理解runtime的原理不仅能帮助去学习runtime,也能去帮助我们更深入的了解OC对象的实现。接下来我们就来了解一下OC一些对象的组成和原理:

类的理解

objc_class 类对象

在OC中我们使用类,但是都是封装成类名,那么对象(object),类(class)底层是怎么封装的?

我们可以查找Class的定义,可以看到它是个objc_class类型的对象,而objc_class则是C语言中的结构体。

typedef struct objc_class *Class;
struct objc_class {
    Class _Nonnull isa;

#if !__OBJC2__
  // 父类
    Class _Nullable super_class;
 // 类名
    const char * _Nonnull name;
// 版本
    long version;
// 其他信息
    long info;
// 实例方法大小
    long instance_size;
// 属性列表
    struct objc_ivar_list * _Nullable ivars ;
// 方法列表
    struct objc_method_list * _Nullable * _Nullable methodLists;
// 缓存对象
    struct objc_cache * _Nonnull cache;
// 协议列表
    struct objc_protocol_list * _Nullable protocols ;
#endif

} OBJC2_UNAVAILABLE;

类对象就是一个结构体,这个结构体存放的数据称为元数据(metadata),,objc_class中包含所定义的属性,方法,协议。同时还有为了优化运行时的效率而定义的缓存cache,所属的父类super_class的Class,以及该类的isa指针。

objc_object 实例对象

我们通过一个类创建一个对象,这个对象本身也是一个结构体objc_object,该结构体是指向Class的isa指针:

struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

说明类创建的对象本质是一个指向Class的指针对象。

isa指针和元类(Meta Class)

类对象中的元数据存储的都是如何创建一个实例的相关信息,那么类对象和类方法应该从哪里创建呢?就是从isa指针指向的结构体创建,类对象的isa指针指向的我们称之为元类(metaclass)

objc_class也是一个对象,在objc_objectobjc_class中我们看到都定义了isa指针,找到其继承通过isa指针。objc_object指向的是objc_class,而objc_class指向的元类类的Meta Class同时通过super_class指向的父类的super_class

这样的一个流程可以从子类对象根据isasuperClass层层找到元类(metaclass),因此isa是指向元类,通过superClass指针指向父类,通过这种方法可以去建立层次关系。

例如,定义一个NSString对象:

NSString *str = @"name";

其通过isa指针和superClass参数建立的指向关系:
NSString对象->NSString类对象->NString元类->NSObject元类
NSString对象->NSString类对象->NSObject类对象(superClass)->通过isa指向NSObject元类

runtime之理解“类”_第1张图片
class关系图.png

如上图所示,相对于 isa对象指向 ClassClass指向 metaClass;相对于 superClassClass指向 superClass。这样 superClassisa指向也 supermetaClass;最终指向 rootMetaClass

objc_method_list

每个Class都有对应的cachemethodLists,当调用方法时,通过这两者,找到对应的目标objc_method执行过程。其中objc_method包括:选择子、方法类型、IMP指针。objc_ cache而缓存的目的是为了优化再次调用方法时,可以直接获取。

struct objc_method {
    SEL method_name;
    char * method_types;
    IMP method_imp;
};

struct objc_method_list {
    struct objc_method_list * obsolete;

    int method_count;
#ifdef __LP64__
    int space
#endif
    struct objc_method method_list[1];
};

前篇讲过消息传递的过程,当对象调用消息时:
先判断接收者(receiver)是否为nil
再通过对象isa指针找到所属Class
查找对应的cache,如果有存在该选择子(SEL)的objc_method对象,转发IMP返回的值;
如果cache不存在,去查找该ClassmethodLists列表,找到存入cache中,并执行IMP
如果methodLists也不存在,通过super_class查找父类,与前面一样查找父类的cachemethodLists如果都没有找到,就执行消息转发。

你可能感兴趣的:(runtime之理解“类”)