美文网首页iOS开发之深入理解runtimeRuntime源码iOS
iOS开发之runtime(9):_objc_init()了解一

iOS开发之runtime(9):_objc_init()了解一

作者: kyson老师 | 来源:发表于2018-12-23 22:59 被阅读45次

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

    runtime logo

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


    背景

    上一篇文章中,我们清除了Win32的相关逻辑。本篇文章将继续带大家研究_objc_init()方法,其中可能会涉及到:

    1. 清理一些与我们理解_objc_init()无帮助或者可能导致模糊的代码
    2. 介绍头文件objc-private.h

    详细

    之前的文章我们有说过_objc_init()方法是runtime被加载后第一个执行的方法。这个方法有如下几个函数:

    void _objc_init(void)
    {
        environ_init();
        tls_init();
        static_init();
        lock_init();
        exception_init();
    
        _dyld_objc_notify_register(&map_2_images, load_images, unmap_image);
    }
    

    其中
    environ_init()方法之前的文章已经有提过
    tls_init()方法这里先不多做介绍,因为涉及的知识面比较广,后面的文章会给于详细解释static_init()也非常有意思,涉及到mach-o文件的构成,这里先不做过多介绍,后面再解释
    lock_init()从名字可以看出是跟锁相关
    exception_init()跟异常相关
    _dyld_objc_notify_register是这个方法的主角,我们点进去看他的介绍:


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


    意思是dyld专门为runtime设计的方法。关于dyld这里也先不多做介绍了,后面的文章会详细介绍的。

    这里笔者要提醒读者的是:

    我们如何找到一个方法的实现

    是的,其实不论是在点击lock_init()还是点击exception_init()我们很可能点击到错误的实现里。

    exception_init方法

    如图,搜索结果有多个方法,但真正objc_init()调用的下图的


    实际调用的exception_init方法

    那么为何第一张图的exception_init方法未执行,而第二张的执行了呢,这里我们又看到了一个关键宏:

    #if !__OBJC2__
    

    按上一篇的思路,我们继续编写测试程序如下:

    int main() {
        printf("__OBJC2__: %d\n",__OBJC2__);
    }
    

    运行后看到后台有如下输出:

    __OBJC2__: 1
    Program ended with exit code: 0
    

    笔者没有找到官方的文档对于__OBJC2__的定义,但从字面意思来看就是判断宏内的代码是不是运行在Objective-C 2.0上的,而大部分iOS开发者都知道,我们目前使用的Objective-C 是 2.0的,因此这个宏返回的是true。

    既然知道了这一点,我们可以对文件 objc-exception.mm 做一些删减:
    *#if !__OBJC2__后面的代码清理掉,结果如下:

    清理后的代码

    推而广之,我们全局搜索#if !__OBJC2__可以做相似的操作:

    搜索“OBJC2”的部分结果

    其他

    全局搜索_objc_init(可以发现,_objc_init()方法的定义位于文件 objc-internal.h 中:

    // Initializer called by libSystem
    OBJC_EXPORT void _objc_init(void)
    

    lock_init方法位于 objc-private.h 中:

    extern void lock_init(void);
    

    同样的,还有tls_init位于 objc-private.h 中:

    extern void tls_init(void);
    

    objc-private.h 和 objc-internal.h 文件后面这两个文件大家后面会经常接触,这里先有个了解:对,这两个文件很重要。


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


    相关文章

      网友评论

        本文标题:iOS开发之runtime(9):_objc_init()了解一

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