手把手帶你探索load底層原理

load的調用規則

  1. 類的load方法在全部父類的load方法調用以後調用
  2. 分類的load方法在當前類的load方法調用以後調用
  3. 分類的load方法的調用順序和編譯順序有關

探索

和上篇文章手把手帶你探索Category底層原理同樣,直接打開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?
    environ_init();
    tls_init();
    static_init();
    lock_init();
    exception_init();

    _dyld_objc_notify_register(&map_images, load_images, unmap_image);
}
複製代碼
  • 前面提到load_images是dyld初始化加載image方法,因此此次應該探索這個方法
void load_images(const char *path __unused, const struct mach_header *mh) {
    // Return without taking locks if there are no +load methods here.
    if (!hasLoadMethods((const headerType *)mh)) return;

    recursive_mutex_locker_t lock(loadMethodLock);

    // Discover load methods
    {
        mutex_locker_t lock2(runtimeLock);
        /** 準備 */
        prepare_load_methods((const headerType *)mh);
    }

    // Call +load methods (without runtimeLock - re-entrant)
    call_load_methods();
}
複製代碼
  • 找到了咱們想要看的load方法,先去探索prepare_load_methods作了什麼,等會再去看call_load_methods
void prepare_load_methods(const headerType *mhdr) {
    size_t count, i;

    runtimeLock.assertLocked();

    //從 Macho 文件加載類的列表
    classref_t *classlist = 
        _getObjc2NonlazyClassList(mhdr, &count);
    for (i = 0; i < count; i++) {
        //數組:[<cls,method>,<cls,method>,<cls,method>] 有順序
        schedule_class_load(remapClass(classlist[i]));
    }

    //針對分類的操做!
    category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
    for (i = 0; i < count; i++) {
        category_t *cat = categorylist[i];
        Class cls = remapClass(cat->cls);
        if (!cls) continue;  // category for ignored weak-linked class
        realizeClass(cls);
        assert(cls->ISA()->isRealized());
        add_category_to_loadable_list(cat);
    }
}
複製代碼
  • getObjc2NonlazyClassListMach-O文件裏獲取了非懶加載的類列表,而後循環類列表,調用了一個遞歸方法schedule_class_load
  • 看看schedule_class_load幹了什麼
  • schedule_class_load是遞歸調用父類,一直往上找父類並調用,因此這裏論證了咱們文章開頭的第一條結論:類的load方法在全部父類的load方法調用以後調用
  • 那麼再看看add_class_to_loadable_list
  • 回到外面
//針對分類的操做!
    category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
    for (i = 0; i < count; i++) {
        category_t *cat = categorylist[i];
        Class cls = remapClass(cat->cls);
        if (!cls) continue;  // category for ignored weak-linked class
        realizeClass(cls);
        assert(cls->ISA()->isRealized());
        add_category_to_loadable_list(cat);
    }
複製代碼
  • 能夠看到分類也是從Mach-O文件中得到的非懶加載分類,這裏剛好驗證了分類的load方法的調用順序和編譯順序有關,編譯順序不一樣,load方法調用的順序不一樣markdown

  • add_category_to_loadable_list再看看這個方法作了什麼 函數

  • 這裏和上面的add_class_to_loadable_list相似,只是換成加載到了分類的全局容器中post

  • 至此,整個prepare_load_methods探索完了,再回頭看看call_load_methods作了什麼 spa

  • 能夠看到,這裏是先調用類的load方法,再調用了分類的load方法,正好驗證了開頭的結論二: 分類的load方法在當前類的load方法調用以後調用ssr

  • call_class_loads就是經過load的SEL調用該方法 code

  • call_category_loads同理 orm

總結

相關文章
相關標籤/搜索