iOS开发之runtime(27): _read_images

作者: kyson老师 | 来源:发表于2019-05-17 00:54 被阅读3次

    本系列博客是本人的源码阅读笔记,如果有 iOS 开发者在看 runtime 的,欢迎大家多多交流。为了方便讨论,本人新建了一个微信群(iOS技术讨论群),想要加入的,请添加本人微信:zhujinhui207407,【加我前请备注:ios 】,本人博客http://www.kyson.cn 也在不停的更新中,欢迎一起讨论

    runtime logo

    本文完整版详见笔者小专栏:https://xiaozhuanlan.com/runtime

    概述

    今天我们开始讲解 map_images_nolock 中调用的最后一个方法:_read_images,其调用路径为:

    - void _objc_init(void)
        - void _dyld_objc_notify_register();
            - void map_2_images();
                - void map_images_nolock();
                    - void _read_images();
    

    这个方法作用就是读取各个 section 中的数据并放到缓存中,这里的缓存大部分都是全局静态变量,载体就是我们之前分析的 hashmap,我们先回顾上一篇文章中的所有 hashmap:
    pendingInitializeMap 、 category_map 、nonmeta_class_map 、future_named_class_map 、remapped_class_map 、protocol_map 、gdb_objc_realized_classes。
    我们把这里面的 hashmap 分为几类:

    • 关于 class 的:
      gdb_objc_realized_classes、remapped_class_map、future_named_class_map、nonmeta_class_map

    • 关于 protocol 的:
      protocol_map

    • 关于 category 的:
      category_map

    本文带大家了解 _read_images 方法的过程中会揭开其中的几个 hashmap 的作用。

    _read_images 源代码如下(过滤一些,只留下主要代码)

    if (!doneOnce) {
        gdb_objc_realized_classes = NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
    }
    
    for (EACH_HEADER) {
        classref_t *classlist = _getObjc2ClassList(hi, &count);
    }
    
    for (EACH_HEADER) {
        Class *classrefs = _getObjc2ClassRefs(hi, &count);
    }
    
    for (EACH_HEADER) {
        SEL *sels = _getObjc2SelectorRefs(hi, &count);
    }
    
    for (EACH_HEADER) {
        message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
    }
    
    for (EACH_HEADER) {
        protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
    }
    
    for (EACH_HEADER) {
        protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);
    }
    
    for (EACH_HEADER) {
        classref_t *classlist = _getObjc2NonlazyClassList(hi, &count);
    }
    
    for (EACH_HEADER) {
        category_t **catlist = 
            _getObjc2CategoryList(hi, &count);
    }
    

    发现很多类似的方法,这些方法在笔者之前的文章中已经讲解过,都是获取 section 的方法:

    //      function name                 content type     section name
    GETSECT(_getObjc2SelectorRefs,        SEL,             "__objc_selrefs"); 
    GETSECT(_getObjc2MessageRefs,         message_ref_t,   "__objc_msgrefs"); 
    GETSECT(_getObjc2ClassRefs,           Class,           "__objc_classrefs");
    GETSECT(_getObjc2SuperRefs,           Class,           "__objc_superrefs");
    GETSECT(_getObjc2ClassList,           classref_t,      "__objc_classlist");
    GETSECT(_getObjc2NonlazyClassList,    classref_t,      "__objc_nlclslist");
    GETSECT(_getObjc2CategoryList,        category_t *,    "__objc_catlist");
    GETSECT(_getObjc2NonlazyCategoryList, category_t *,    "__objc_nlcatlist");
    GETSECT(_getObjc2ProtocolList,        protocol_t *,    "__objc_protolist");
    GETSECT(_getObjc2ProtocolRefs,        protocol_t *,    "__objc_protorefs");
    

    总结如下:

    section名 调用的方法 返回类型
    __objc_classlist _getObjc2ClassList classref_t
    __objc_selrefs _getObjc2SelectorRefs SEL
    __objc_msgrefs _getObjc2MessageRefs message_ref_t
    __objc_protolist _getObjc2ProtocolList protocol_t
    __objc_protorefs _getObjc2ProtocolRefs protocol_t
    __objc_nlclslist _getObjc2NonlazyClassList classref_t
    __objc_catlist _getObjc2CategoryList category_t

    因此 _read_images 方法的作用也很明显了: 把对应 section 里的数据取出来,然后进行加工,最后添加到缓存中。虽然说 _read_images 只有几百行,但其中又会调用其他很多方法,因此总的来说 _read_images 方法还是比较复杂的。这里只摘取一些 section 数据获取后的处理流程。

    __objc_classlist

    之前已经大概说过 __objc_classlist 这个 section 表示的是项目中全部类列表,与之关联的一个 section 为: __objc_classrefs ,表示项目中被引用的类列表。列一张表看一下:

    __objc_classlist __objc_classrefs
    含义 项目中全部类列表 项目中被引用的类列表
    对应方法 _getObjc2ClassList _getObjc2ClassRefs
    对应全局变量 gdb_objc_realized_classes noClassesRemapped

    这两个 section 的数据都在 _read_images 方法中,这里做个大概讲解:

    • 创建:
    gdb_objc_realized_classes =
        NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
    
    • 插入:
    - Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
        - addNamedClass(cls, mangledName, replacing);
            - NXMapInsert(gdb_objc_realized_classes, name, cls);
    

    __objc_selrefs

    __objc_selrefs
    含义 方法列表
    方法名 _getObjc2SelectorRefs
    对应全局变量 namedSelectors
    • 创建
    namedSelectors = NXCreateMapTable(NXStrValueMapPrototype, 
                                              (unsigned)SelrefCount);
    
    • 插入
    NXMapInsert(namedSelectors, sel_getName(result), result);
    
    • 获取
    result = (SEL)NXMapGet(namedSelectors, name);
    

    读者可以自行找到这几段代码的位置。


    文章完整版请见笔者小专栏:https://xiaozhuanlan.com/runtime


    总结

    本文讲解了 _read_images 函数的作用是获取各个 section 中的数据并在此基础上做一些处理,希望对大家有所帮助。最后用一幅图总结一下本文涉及到的 section:


    section

    相关文章

      网友评论

        本文标题:iOS开发之runtime(27): _read_images

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