美文网首页iOS开发之深入理解runtime
iOS开发之 runtime(29) :gdb_objc_rea

iOS开发之 runtime(29) :gdb_objc_rea

作者: kyson老师 | 来源:发表于2019-06-06 22:01 被阅读0次

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

    runtime logo

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

    概述

    我们在iOS开发之runtime(27): _read_images 浅析中讲解了 class 相关的多个 hash 表:

    • gdb_objc_realized_classes
    • remapped_class_map
    • future_named_class_map
    • nonmeta_class_map

    本文我们就详细的分析一下这几个 hash map 的第一个: gdb_objc_realized_classes。

    gdb_objc_realized_classes
    gdb_objc_realized_classes is actually a list of named classes not in the dyld shared cache, whether realized or not.

    这段文字出现在文件 objc_runtime_new.mm 中:


    gdb_objc_realized_classes

    这里翻译一下:
    gdb_objc_realized_classes 是一系列的类列表,这些类不管有没有实现都不在 dyld 的共享缓存中。
    全局搜索 gdb_objc_realized_classes,我们可以看到一系列方法,


    搜索 gdb_objc_realized_classes

    这些方法涉及到对于 gdb_objc_realized_classes 的一系列操作,包括:

    获取某个类:

    static Class getClass_impl(const char *name)
    {
        runtimeLock.assertLocked();
        // allocated in _read_images
        assert(gdb_objc_realized_classes);
        // Try runtime-allocated table
        Class result = (Class)NXMapGet(gdb_objc_realized_classes, name);
        if (result) return result;
        // Try table from dyld shared cache
        return getPreoptimizedClass(name);
    }
    

    添加某个类:

    /***********************************************************************
    * addNamedClass
    * Adds name => cls to the named non-meta class map.
    * Warns about duplicate class names and keeps the old mapping.
    * Locking: runtimeLock must be held by the caller
    **********************************************************************/
    static void addNamedClass(Class cls, const char *name, Class replacing = nil)
    {
        runtimeLock.assertWriting();
        Class old;
        if ((old = getClass(name))  &&  old != replacing) {
            inform_duplicate(name, old, cls);
    
            // getNonMetaClass uses name lookups. Classes not found by name 
            // lookup must be in the secondary meta->nonmeta table.
            addNonMetaClass(cls);
        } else {
            NXMapInsert(gdb_objc_realized_classes, name, cls);
        }
        assert(!(cls->data()->flags & RO_META));
    
        // wrong: constructed classes are already realized when they get here
        // assert(!cls->isRealized());
    }
    

    移除某个类:

    /***********************************************************************
    * removeNamedClass
    * Removes cls from the name => cls map.
    * Locking: runtimeLock must be held by the caller
    **********************************************************************/
    static void removeNamedClass(Class cls, const char *name)
    {
        runtimeLock.assertWriting();
        assert(!(cls->data()->flags & RO_META));
        if (cls == NXMapGet(gdb_objc_realized_classes, name)) {
            NXMapRemove(gdb_objc_realized_classes, name);
        } else {
            // cls has a name collision with another class - don't remove the other
            // but do remove cls from the secondary metaclass->class map.
            removeNonMetaClass(cls);
        }
    }
    

    而初始化的位置就是我们所知道的 _read_images 方法中:

    // namedClasses
    // Preoptimized classes don't go in this table.
    // 4/3 is NXMapTable's load factor
    int namedClassesSize = 
        (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
    gdb_objc_realized_classes =
        NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
    

    add 方法的也位于 _read_images 调用栈中:

    - void _objc_init(void)
        - void _dyld_objc_notify_register();
            - void map_2_images();
                - void map_images_nolock();
                    - void _read_images();
                        - Class readClass();
                            - void addNamedClass();
    

    需要注意的是:

    addNamedClass(cls, mangledName, replacing);
    

    的第二个参数是 mangledName, 也就是上一篇文章笔者 Demo 中给大家从 section 中获取的数据。
    现在看来,gdb_objc_realized_classes 的作用已经很明显了,即是对所有的类进行缓存:从对应的 section 中读取所有的类,取出来后以 mangledName 作为键,以 class 结构体作为值。

    至此 gdb_objc_realized_classes 分析结束。

    广告

    我的首款个人开发的APP壁纸宝贝上线了,欢迎大家下载。

    壁纸宝贝

    相关文章

      网友评论

        本文标题:iOS开发之 runtime(29) :gdb_objc_rea

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