美文网首页iOS开发之深入理解runtimeRuntime源码iOS
iOS开发之runtime(20):sel_init()分析

iOS开发之runtime(20):sel_init()分析

作者: kyson老师 | 来源:发表于2019-02-13 21:56 被阅读15次

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

    runtime logo

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

    背景

    sel_init()的调用栈如下

    -| _objc_init()
       -| _dyld_objc_notify_register
         -| map_images_nolock()
           -| sel_init()
    

    其代码如下:

    /***********************************************************************
    * sel_init
    * Initialize selector tables and register selectors used internally.
    **********************************************************************/
    void sel_init(size_t selrefCount)
    {
        // save this value for later
        SelrefCount = selrefCount;
    
        builtins = preoptimizedSelectors();
        if (PrintPreopt  &&  builtins) {
            uint32_t occupied = builtins->occupied;
            uint32_t capacity = builtins->capacity;
            
            _objc_inform("PREOPTIMIZATION: using selopt at %p", builtins);
            _objc_inform("PREOPTIMIZATION: %u selectors", occupied);
            _objc_inform("PREOPTIMIZATION: %u/%u (%u%%) hash table occupancy",
                         occupied, capacity,
                         (unsigned)(occupied/(double)capacity*100));
        }
    
    #define s(x) SEL_##x = sel_registerNameNoLock(#x, NO)
    #define t(x,y) SEL_##y = sel_registerNameNoLock(#x, NO)
    
        sel_lock();
        
        s(load);
        s(initialize);
        t(resolveInstanceMethod:, resolveInstanceMethod);    
        t(resolveClassMethod:, resolveClassMethod);
        t(.cxx_construct, cxx_construct);
        t(.cxx_destruct, cxx_destruct);
        s(retain);
        s(release);
        s(autorelease);
        s(retainCount);
        s(alloc);
        t(allocWithZone:, allocWithZone);
        s(dealloc);
        s(copy);
        s(new);
        t(forwardInvocation:, forwardInvocation);
        t(_tryRetain, tryRetain);
        t(_isDeallocating, isDeallocating);
        s(retainWeakReference);
        s(allowsWeakReference);
    
        sel_unlock();
    
    #undef s
    #undef t
    }
    

    本文就带读者分析一下其源代码。

    分析

    宏的用法,以上的代码中有一个宏:

    #define s(x) SEL_##x = sel_registerNameNoLock(#x, NO)
    

    可能比较少人会了解###的用法。

    #表示:对应变量字符串化
    ##表示:把宏参数名与宏定义代码序列中的标识符连接在一起,形成一个新的标识符

    因此s(load);会被替换成:

    SEL_load = sel_registerNameNoLock("load",NO);
    

    t(resolveInstanceMethod:, resolveInstanceMethod);
    

    会被改写成:

    SEL_resolveInstanceMethod = sel_registerNameNoLock("resolveInstanceMethod:",NO);
    

    我们进入sel_registerNameNoLock方法的定义中看:

    SEL sel_registerNameNoLock(const char *name, bool copy) {
        return __sel_registerName(name, 0, copy);  // NO lock, maybe copy
    }
    

    __sel_registerName的定义如下:

    static SEL __sel_registerName(const char *name, int lock, int copy) 
    {
        SEL result = 0;
    
        if (lock) selLock.assertUnlocked();
        else selLock.assertWriting();
    
        if (!name) return (SEL)0;
    
        result = search_builtins(name);
        if (result) return result;
        
        if (lock) selLock.read();
        if (namedSelectors) {
            result = (SEL)NXMapGet(namedSelectors, name);
        }
        if (lock) selLock.unlockRead();
        if (result) return result;
    
        // No match. Insert.
    
        if (lock) selLock.write();
    
        if (!namedSelectors) {
            namedSelectors = NXCreateMapTable(NXStrValueMapPrototype, 
                                              (unsigned)SelrefCount);
        }
        if (lock) {
            // Rescan in case it was added while we dropped the lock
            result = (SEL)NXMapGet(namedSelectors, name);
        }
        if (!result) {
            result = sel_alloc(name, copy);
            // fixme choose a better container (hash not map for starters)
            NXMapInsert(namedSelectors, sel_getName(result), result);
        }
    
        if (lock) selLock.unlockWrite();
        return result;
    }
    

    可以发现,这个方法其实是讲selector添加到MapTable中,关于MapTable这里先不做介绍了,后面的文章会给出详细分析。
    需要注意的是,被注册的selector会被放到一个静态变量namedSelectors中:

    static NXMapTable *namedSelectors;
    

    至此sel_init分析完成。

    相关文章

      网友评论

        本文标题:iOS开发之runtime(20):sel_init()分析

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