第二篇 Runtime消息传递

一个对象的方法像这样[obj doing],编译器转成消息发送objc_msgSend(obj, doing),Runtime时执行的流程是这样的:
(1)通过objisa指针找到它的class;
(2)在classmethod listdoing(直接在cache里找到,避免去遍历objc_method_list);
(3)如果class中没到doing,继续往它的superclass中找 ;
(4)一旦找到doing这个函数,就去执行它的实现IMP

实例:isa指针指向的结构体创建,类对象的isa指针指向的我们称之为元类(metaclass),
元类中保存了创建类对象以及类方法所需的所有信息。

struct objc_object {
     Class isa  OBJC_ISA_AVAILABILITY;  // isa指针
};

类对象:Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。

struct objc_class {
     Class isa  OBJC_ISA_AVAILABILITY;           // isa指针
     #if !__OBJC2__
         Class super_class                       OBJC2_UNAVAILABLE; // 指向父类指针
         const char *name                        OBJC2_UNAVAILABLE; // 类的名字
         long version                            OBJC2_UNAVAILABLE;
         long info                               OBJC2_UNAVAILABLE; // 版本
         long instance_size                      OBJC2_UNAVAILABLE; // 实例大小
         struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE; // 实例变量列表
         struct objc_method_list **methodLists   OBJC2_UNAVAILABLE; // 方法列表
         struct objc_cache *cache                OBJC2_UNAVAILABLE; // 缓存
         struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE; // 遵守的协议列表
     #endif
} OBJC2_UNAVAILABLE;

方法列表

struct objc_method_list {
     struct objc_method_list *obsolete        OBJC2_UNAVAILABLE;
     int method_count                         OBJC2_UNAVAILABLE;
     #ifdef __LP64__
         int space                            OBJC2_UNAVAILABLE;
     #endif
     /* variable length structure */
    struct objc_method method_list[1]         OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;

方法:方法表示能够独立完成一个功能的一段代码

struct objc_method {
    SEL method_name           OBJC2_UNAVAILABLE; // 方法名
    char *method_types        OBJC2_UNAVAILABLE; // 方法类型
    IMP method_imp            OBJC2_UNAVAILABLE; // 方法实现
}

SEL:
(1)SELselector在Objective-C中的表示类型(Swift中是Selector类)。selector是方法选择器,可以理解为区分方法的ID,而这个ID的数据结构是SEL
(2)selectorSEL的一个实例。
(3)selector就是个映射到方法的C字符串,你可以用Objective-C编译器命令@selector()或者Runtime系统的sel_registerName函数来获得一个 SEL 类型的方法选择器。
(4)selector既然是一个string,命名规则有两条:同一个类,selector不能重复;不同的类,selector可以重复。

IMP
指向最终实现程序的内存地址的指针。

类缓存:加速消息分发,系统会对方法和对应的地址进行缓存

struct objc_cache {
    unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE; // 缓存的size
    unsigned int occupied                                    OBJC2_UNAVAILABLE; // 当前被占用的数目(缓存以散列表的形式存在)
    Method _Nullable buckets[1]                              OBJC2_UNAVAILABLE; // 用数组表示的hashtable(cache_entry类型,代表一个方法缓存)
};

方法缓存的类型

struct cache_entry {
    SEL name;     // 被缓存的方法名
    void *unused; // 未被使用的保留字段
    IMP imp;      // 方法实现
};

Category:表示一个指向分类的结构体的指针

struct category_t {
    const char *name;                               // class_name
    classref_t cls;                                 // 要扩展的类对象,编译时不定义,在运行时通过name对应到对应的类对象
    struct method_list_t *instanceMethods;          // 所有给类添加的实例方法的列表
    struct method_list_t *classMethods;             // 所有添加的类方法的列表
    struct protocol_list_t *protocols;              // 实现的所有协议的列表
    struct property_list_t *instanceProperties;     // 所有的properties(是我们可以通过objc_setAssociatedObject和objc_getAssociatedObject增加实例变量的原因)
};

猜你喜欢

转载自blog.csdn.net/potato512/article/details/80946949