iOS开发之深入理解runtimeiOSios开发

iOS开发之runtime(27): _read_images

2019-05-17  本文已影响3人  kyson老师

本系列博客是本人的源码阅读笔记,如果有 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 分为几类:

本文带大家了解 _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
上一篇 下一篇

猜你喜欢

热点阅读