运行时(Runtime)篇幅二

117 阅读4分钟

篇幅一中从objc_method出发了解了方法的主要底层逻辑。本篇的开始先来思考个问题:消息的接收者是谁以及运行期系统是如何来确定接收者的类型

首先得知道对象类型并非在编译期确定,而是在运行期查找,其中在运行期对类型信息查询这一操作被称之为内省

再次每个Objective-C对象的实例都是指向某块内存数据的指针。例:

Person *person = [[Person alloc] init];

person实例对象(instance) 可以理解成存放内存地址的变量

Person:是一个同时也是一个对象被称为类对象。因为OC的类都是继承自NSObject,所以Person相当于是NSObject的一个对象。

描述Objective-C对象所用的数据结构定义在Runtime库中的定义如下:

struct objc_object {
    Class isa;
};

由此可见每个对象的首个成员是Class类的变量。isa指针定义了该对象所属的类,又或者理解为isa指针指向的该对象的类。那么再来看下Class对象在Runtime库中的定义:

struct objc_class {
    Class isa;
    Class super_class                              
    const char *name                   // 类名            
    long version                       // 类的版本信息                  
    long info                          // 类信息                  
    long instance_size                 // 实例变量大小                  
    struct objc_ivar_list *ivars                  
    struct objc_method_list **methodLists         
    struct objc_cache *cache                       
    struct objc_protocol_list *protocols          // 协议列表
}

Class isa:是Class的首个成员变量是一个isa的指针,这也证明了Class本身也是个Objective-C的对象。该Class被称为类对象,该isa指针指向的是另一个类叫做元类,且描述了实例所属的类。

元类用来表示类对象本身所具备的元数据。类方法就定义与此,这些方法可以理解为类对象的实例方法。每个类仅有一个“类对象”,每个“类对象”仅有一个与之先关的“元类”。

Class super_class:定义了当前类的超类,通过super_class指针来确立类对象的isa指针所指向的元类

objc_ivar_list *ivars: ivars是一个指向objc_ivar_list的指针。


objc_ivar_list在Runtime库中的定义:

struct objc_ivar_list {
    int ivar_count                                       
    int space                                                
    struct objc_ivar ivar_list[1]                            
}

objc_ivar_list是OC中代表类的实例的变量列表; ivar_count用于存储属性数量;objc_ivar是表示一个实例变量的数据结构;ivar_list用于存储Ivar[1]表示变长结构体具体实现的细节。

// Ivar在Runtime库中的定义:
typedef struct objc_ivar *Ivar;
struct objc_ivar {
    char *ivar_name                               
    char *ivar_type                               
    int ivar_offset                                          
    int space                                                
}                                                            

前三个属性分别代表着:名称、类型、内存偏移量
属性生成过程可分一下几部:
1. 创建属性,设置objc_ivar,通过偏移量和内存占用就可以方便获取
2.生成getter和setter方法
3.将属性的ivar添加到类的ivar_list中,作为类的成员变量存在
4.将getter和setter方法加入类的method_list中
5.将属性描述添加到类的属性描述列表中


objc_method_list **methodLists:类的方法的定义列表,存储着类的单个方法的所有信息。 objc_cache *cache:方法的缓存列表

篇幅一中讲解方法查询顺序时讲解到会优先查找缓存列表中的方法目的是增加方法调用的查找速度从而提高效率。
此时可以引出一些方法调用的结论,接着用Person来举例:

[person stringForWord];
[Person man];

person是类Person的实例,是一个实例方法。首先会通过objc_object结构体找到对应的Person类,在从类的缓存方法列表中查找,没有则再从方法列表中查找;如果当前类中没有对应的方法,则根据当前类的super_class指针查找到对应类的父类,查询顺序优先缓存列表在方法列表,一直往上查找直至NSObject
而第二个类方法则直接通过Class结构体中的isa指针查找对应的meta-class(元类)对象,没有则通过元类的super_class指针往上查找,直至根元类

如此一来跟篇幅一的内容也有所关联。本来是想直接从objc_ivar *Ivar直接讲其,但关乎到其真实存在的意义并非其本身而是整个对象或则类。从而也通过对象类来关联方法的底层原理,如此一来也更为方便理解。