iOS开发技巧

OC底层原理11—dyld与objc的关联

2020-10-16  本文已影响0人  夏天的枫_

本文介绍dyld与objc的关联

按照苹果的解释,dyld加载库时,libSystem会调用_objc_init,用dyld注册镜像程序。那来看看Objc中的初始化_objc_init做了什么

void _objc_init(void)
{
    static bool initialized = false;
    if (initialized) return;
    initialized = true;
    
    // fixme defer initialization until an objc-using image is found?
    //读取影响运行时的环境变量,如果需要,还可以打开环境变量帮助 export OBJC_HRLP = 1
    environ_init();
    //关于线程key的绑定,例如线程数据的析构函数
    tls_init();
    //运行C++静态构造函数,在dyld调用我们的静态析构函数之前,libc会调用_objc_init(),因此我们必须自己做
    static_init();
    //runtime运行时环境初始化,里面主要是unattachedCategories、allocatedClasses -- 分类初始化
    runtime_init();
    //初始化libobjc的异常处理系统
    exception_init();
    //缓存条件初始化
    cache_init();
    //启动回调机制,通常这不会做什么,因为所有的初始化都是惰性的,但是对于某些进程,我们会迫不及待地加载trampolines dylib
    _imp_implementationWithBlock_init();

    /*
     _dyld_objc_notify_register -- dyld 注册的地方
     - 仅供objc运行时使用
     - 注册处理程序,以便在映射、取消映射 和初始化objc镜像文件时使用,dyld将使用包含objc_image_info的镜像文件数组,回调 mapped 函数
     map_images: dyld将image镜像文件加载进内存时,会触发该函数
     load_images:dyld初始化image会触发该函数
     unmap_image:dyld将image移除时会触发该函数
     */
    _dyld_objc_notify_register(&map_images, load_images, unmap_image);

#if __OBJC2__
    didCallDyldNotifyRegister = true;
#endif
}

dyld_objc_notify_register

这是dyld注册处理程序

_dyld_objc_notify_register(&map_images, load_images, unmap_image);

dyld源码中找到该方法的解释

//
// Note: only for use by objc runtime
// Register handlers to be called when objc images are mapped, unmapped, and initialized.
// Dyld will call back the "mapped" function with an array of images that contain an objc-image-info section.
// Those images that are dylibs will have the ref-counts automatically bumped, so objc will no longer need to
// call dlopen() on them to keep them from being unloaded.  During the call to _dyld_objc_notify_register(),
// dyld will call the "mapped" function with already loaded objc images.  During any later dlopen() call,
// dyld will also call the "mapped" function.  Dyld will call the "init" function when dyld would be called
// initializers in that image.  This is when objc calls any +load methods in that image.
//
void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
                                _dyld_objc_notify_init      init,
                                _dyld_objc_notify_unmapped  unmapped);
{
  dyld::registerObjCNotifiers(mapped, init, unmapped);
}

注意:仅供objc运行时使用
在objc镜像映射、未映射和初始化时调用,用来注册处理程序。
dyld将会通过一个包含objc-image-info的镜像文件的数组回调mapped函数。
那些是dylibs的镜像将自动增加引用计数,因此objc以防止它们被卸载,将不再需要
对它们调用dlopen()。 在调用_dyld_objc_notify_register()的过程中,dyld将使用已加载的objc镜像调用“mapped”函数。 在以后的任何dlopen()调用期间,dyld也将调用“mapped”函数。
当调用dyld时,dyld将调用“ init”函数初始化镜像。
objc镜像在调用任何类方法+load()的时候,也会初始化。

方法中的三个参数分别表示的含义如下:
map_images:dyld将image(镜像文件)加载进内存时,会触发该函数
load_image:dyld初始化image会触发该函数
unmap_image:dyld将image移除时,会触发该函数


image.png
void registerObjCNotifiers(_dyld_objc_notify_mapped mapped, _dyld_objc_notify_init init, _dyld_objc_notify_unmapped unmapped)
{
    // record functions to call
    sNotifyObjCMapped   = mapped;
    sNotifyObjCInit     = init;
    sNotifyObjCUnmapped = unmapped;

    // call 'mapped' function with all images mapped so far
    try {
        notifyBatchPartial(dyld_image_state_bound, true, NULL, false, true);
    }
    catch (const char* msg) {
        // ignore request to abort during registration
    }

    // <rdar://problem/32209809> call 'init' function on all images already init'ed (below libSystem)
    for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
        ImageLoader* image = *it;
        if ( (image->getState() == dyld_image_state_initialized) && image->notifyObjC() ) {
            dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_INIT, (uint64_t)image->machHeader(), 0, 0);
            (*sNotifyObjCInit)(image->getRealPath(), image->machHeader());
        }
    }
}

在objc中调用初始化时objc_init,会调用 _dyld_objc_notify_register(&map_images, load_images, unmap_image);,在dyld中其实是调用

void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
                                _dyld_objc_notify_init      init,
                                _dyld_objc_notify_unmapped  unmapped);
{
  dyld::registerObjCNotifiers(mapped, init, unmapped);
}

分析registerObjCNotifiers实现,得到了
map_images = sNotifyObjCMapped = mapped
load_images = sNotifyObjCInit = init
unmap_image = sNotifyObjCUnmapped = unmapped

上一篇下一篇

猜你喜欢

热点阅读