iOS RunTime 总结

RunTime

RunTime简称运行时。就是系统在运行的时候的一些机制,其中最主要的是消息机制bash

RunTime的2个重要特种ui

  • C++等语言,在编译时就已经肯定了,运行时就是找到内存的位置,而后执行代码;而在Objective-C中,方法的调用其实是以一种叫“消息转发”的方式进行的,也就是告诉class/object,我要调用某个object/class的某个方法;可是!具体是否调用某个方法,如何调用,能够在运行时决定和修改。
  • class/object/method…的本质都是struct,所以在运行时也能够进行修改。

Class

先来看下 Class 的定义:spa

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
复制代码

实际上Class就是 objc_class指针

objc_class

在<objc/runtime.h>中,能够找到一个叫objc_class的struct。咱们看一下这个struct的定义code

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#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;
    //ivar列表,是一个objc_ivar_list类型的指针 表明实例变量
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    // method列表,是一个objc_method_list二级指针
    struct objc_method_list * _Nullable * _Nullable methodLists                 OBJC2_UNAVAILABLE;
    //存储经常使用method,加快消息转发速度
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    //存储实现的protocols
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
复制代码

日常咱们定义了一个class以后,实际上它会被编译成一个这样的struct;咱们定义的变量、方法等,都存储在struct中。cdn

objc_object

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
复制代码

当咱们建立了一个类的实例后,其实生成了一个这样的struct。它里面的的Class isa,能够在消息转发时寻找到对应的classblog

objc_method_list

看一下 objc_class 中的 objc_method_list 定义内存

struct objc_method_list {
    int method_count;
    /* variable length structure */
    struct objc_method method_list[1];
}
复制代码

objc_method_list 里面存储了一个 objc_method字符串

objc_method

struct objc_method {
    SEL method_name;
    char *method_types;
    IMP method_imp;
} 
复制代码

这个objc_method就是咱们熟悉的method。能够看到method主要由方法名、function指针组成,将SELIMP作了一个映射get

SEL

typedef struct objc_selector *SEL;
复制代码

objc_selector就是一个C字符串。所以,SEL其实就是一个字符串,能够理解成是对方法名的hash化

IMP

typedef void (*IMP)(void /* id, SEL, ... */ ); 
复制代码

IMP是方法的具体实现

当咱们调用某个方法时,实际上是向这个object发送一个“消息”,包含了方法名和参数。经过isa 找到objc_class, 而后在objc_class中遍历寻找对应的objc_method,找到以后再调用IMP。 也就是说,方法名SEl和真正的实现代码IMP之间,是由objc_method来绑定的,这样就实现了相对的动态化。

消息传递具体流程

  • 将方法调用转化成objc_msgSend等方法,向object发送消息;
  • 经过objc_objectisa找到其所在class;
  • 检测这个SEL是否是要忽略的;好比ARC中会忽略retain等操做;
  • 检测target是不是nil;若是是的话,就忽略掉;
  • 从cache中找SEL;一旦找到,就执行SEL对应的IMP
  • 若是没有,再到methodLists里找;
  • 若是尚未,再到superclass里找,一直找到NSObject
  • 若是尚未,进入动态方法解析。
相关文章
相关标签/搜索