+(void)load 方法的調(diào)用

objc_init方法中設(shè)置了load_images回調(diào)

void _objc_init(void)
{
···
    _dyld_objc_notify_register(&map_images, load_images, unmap_image);
···
}

load_images

void
load_images(const char *path __unused, const struct mach_header *mh)
{
    if (!didInitialAttachCategories && didCallDyldNotifyRegister) {
        didInitialAttachCategories = true;
// 加載分類
        loadAllCategories();
    }

    // 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);
// 準(zhǔn)備調(diào)用load方法,會(huì)把類的load方法和分類的load方法存儲(chǔ)起來(lái)
        prepare_load_methods((const headerType *)mh);
    }

    // Call +load methods (without runtimeLock - re-entrant)
// 調(diào)用load方法
    call_load_methods();
}

添加load方法到集合

prepare_load_methods

void prepare_load_methods(const headerType *mhdr)
{
    size_t count, i;

    runtimeLock.assertLocked();

    classref_t const *classlist = 
        _getObjc2NonlazyClassList(mhdr, &count);
    for (i = 0; i < count; i++) {
// 增加類的load方法
        schedule_class_load(remapClass(classlist[i]));
    }

    category_t * const *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
        if (cls->isSwiftStable()) {
            _objc_fatal("Swift class extensions and categories on Swift "
                        "classes are not allowed to have +load methods");
        }
        realizeClassWithoutSwift(cls, nil);
        ASSERT(cls->ISA()->isRealized());
// 增加分類的load方法
        add_category_to_loadable_list(cat);
    }
}

schedule_class_load

static void schedule_class_load(Class cls)
{
    if (!cls) return;
    ASSERT(cls->isRealized());  // _read_images should realize

// 判斷是否需要添加
    if (cls->data()->flags & RW_LOADED) return;

    // 遞歸添加父類
    schedule_class_load(cls->getSuperclass());
    // 添加類的load方法
    add_class_to_loadable_list(cls);
// 設(shè)置標(biāo)識(shí),防止重復(fù)添加
    cls->setInfo(RW_LOADED); 
}

add_class_to_loadable_list

void add_class_to_loadable_list(Class cls)
{
    IMP method;

    loadMethodLock.assertLocked();
// 通過(guò)ro列表獲取類的load方法
    method = cls->getLoadMethod();
    if (!method) return;  // Don't bother if cls has no +load method
    
    if (PrintLoading) {
        _objc_inform("LOAD: class '%s' scheduled for +load", 
                     cls->nameForLogging());
    }
    
    if (loadable_classes_used == loadable_classes_allocated) {
        loadable_classes_allocated = loadable_classes_allocated*2 + 16;
        loadable_classes = (struct loadable_class *)
            realloc(loadable_classes,
                              loadable_classes_allocated *
                              sizeof(struct loadable_class));
    }
    // 添加load方法
    loadable_classes[loadable_classes_used].cls = cls;
    loadable_classes[loadable_classes_used].method = method;
    loadable_classes_used++;
}

add_category_to_loadable_list 添加分類的load方法

void add_category_to_loadable_list(Category cat)
{
    IMP method;

    loadMethodLock.assertLocked();
// 獲取分類的load方法
    method = _category_getLoadMethod(cat);

    // Don't bother if cat has no +load method
    if (!method) return;

    if (PrintLoading) {
        _objc_inform("LOAD: category '%s(%s)' scheduled for +load", 
                     _category_getClassName(cat), _category_getName(cat));
    }
    
    if (loadable_categories_used == loadable_categories_allocated) {
        loadable_categories_allocated = loadable_categories_allocated*2 + 16;
        loadable_categories = (struct loadable_category *)
            realloc(loadable_categories,
                              loadable_categories_allocated *
                              sizeof(struct loadable_category));
    }
// 增加分類的load方法
    loadable_categories[loadable_categories_used].cat = cat;
    loadable_categories[loadable_categories_used].method = method;
    loadable_categories_used++;
}

調(diào)用load方法

void call_load_methods(void)
{
    static bool loading = NO;
    bool more_categories;

    loadMethodLock.assertLocked();

    // Re-entrant calls do nothing; the outermost call will finish the job.
    if (loading) return;
    loading = YES;

    void *pool = objc_autoreleasePoolPush();

    do {
        // 1. Repeatedly call class +loads until there aren't any more
        while (loadable_classes_used > 0) {
    //調(diào)用類的load方法
            call_class_loads();
        }

        // 2. Call category +loads ONCE
// 調(diào)用分類的load方法
        more_categories = call_category_loads();

        // 3. Run more +loads if there are classes OR more untried categories
    } while (loadable_classes_used > 0  ||  more_categories);

    objc_autoreleasePoolPop(pool);

    loading = NO;
}

call_class_loads 調(diào)用類的load方法

static void call_class_loads(void)
{
    int i;
    
    // Detach current loadable list.
    struct loadable_class *classes = loadable_classes;
    int used = loadable_classes_used;
    loadable_classes = nil;
    loadable_classes_allocated = 0;
    loadable_classes_used = 0;
    
    // Call all +loads for the detached list.
    for (i = 0; i < used; i++) {
        Class cls = classes[i].cls;
        load_method_t load_method = (load_method_t)classes[i].method;
        if (!cls) continue; 

        if (PrintLoading) {
            _objc_inform("LOAD: +[%s load]\n", cls->nameForLogging());
        }
// 調(diào)用方法
        (*load_method)(cls, @selector(load));
    }
    
    // Destroy the detached list.
    if (classes) free(classes);
}

call_category_loads 調(diào)用分類的load方法

static bool call_category_loads(void)
{
    int i, shift;
    bool new_categories_added = NO;
    
    // Detach current loadable list.
    struct loadable_category *cats = loadable_categories;
    int used = loadable_categories_used;
    int allocated = loadable_categories_allocated;
    loadable_categories = nil;
    loadable_categories_allocated = 0;
    loadable_categories_used = 0;

    // Call all +loads for the detached list.
    for (i = 0; i < used; i++) {
        Category cat = cats[i].cat;
        load_method_t load_method = (load_method_t)cats[i].method;
        Class cls;
        if (!cat) continue;

        cls = _category_getClass(cat);
        if (cls  &&  cls->isLoadable()) {
            if (PrintLoading) {
                _objc_inform("LOAD: +[%s(%s) load]\n", 
                             cls->nameForLogging(), 
                             _category_getName(cat));
            }
// 調(diào)用方法
            (*load_method)(cls, @selector(load));
            cats[i].cat = nil;
        }
    }

    // Compact detached list (order-preserving)
// 刪除空的分類
    shift = 0;
    for (i = 0; i < used; i++) {
        if (cats[i].cat) {
            cats[i-shift] = cats[i];
        } else {
            shift++;
        }
    }
    used -= shift;

    // Copy any new +load candidates from the new list to the detached list.
// 新增加的  分類列表
    new_categories_added = (loadable_categories_used > 0);
    for (i = 0; i < loadable_categories_used; i++) {
        if (used == allocated) {
            allocated = allocated*2 + 16;
            cats = (struct loadable_category *)
                realloc(cats, allocated *
                                  sizeof(struct loadable_category));
        }
        cats[used++] = loadable_categories[i];
    }

    // 銷毀新增加的分類列表
    if (loadable_categories) free(loadable_categories);

    // Reattach the (now augmented) detached list. 
    // But if there's nothing left to load, destroy the list.
    if (used) { // 有使用的分類
        loadable_categories = cats;
        loadable_categories_used = used;
        loadable_categories_allocated = allocated;
    } else {
        if (cats) free(cats);
        loadable_categories = nil;
        loadable_categories_used = 0;
        loadable_categories_allocated = 0;
    }
···
// 返回在調(diào)用過(guò)程中是否有新增加的分類
    return new_categories_added;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末庆尘,一起剝皮案震驚了整個(gè)濱河市拴孤,隨后出現(xiàn)的幾起案子蛋逾,更是在濱河造成了極大的恐慌嘹悼,老刑警劉巖哨啃,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件割粮,死亡現(xiàn)場(chǎng)離奇詭異争便,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)完疫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門泰鸡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人壳鹤,你說(shuō)我怎么就攤上這事盛龄。” “怎么了芳誓?”我有些...
    開(kāi)封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵余舶,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我锹淌,道長(zhǎng)匿值,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任赂摆,我火速辦了婚禮挟憔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘烟号。我一直安慰自己绊谭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開(kāi)白布汪拥。 她就那樣靜靜地躺著达传,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迫筑。 梳的紋絲不亂的頭發(fā)上宪赶,一...
    開(kāi)封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音铣焊,去河邊找鬼。 笑死罕伯,一個(gè)胖子當(dāng)著我的面吹牛曲伊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播追他,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼坟募,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了邑狸?” 一聲冷哼從身側(cè)響起懈糯,我...
    開(kāi)封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎单雾,沒(méi)想到半個(gè)月后赚哗,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體她紫,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年屿储,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贿讹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡够掠,死狀恐怖民褂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疯潭,我是刑警寧澤赊堪,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站竖哩,受9級(jí)特大地震影響哭廉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜期丰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一群叶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧钝荡,春花似錦街立、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至端辱,卻和暖如春梁剔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舞蔽。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工荣病, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人渗柿。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓个盆,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親朵栖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子颊亮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 精華總結(jié):Category中有l(wèi)oad方法, load方法會(huì)在runtime加載類的時(shí)候調(diào)用 類的load方法調(diào)用...
    二斤寂寞閱讀 2,115評(píng)論 0 3
  • Objective-C之Category的底層實(shí)現(xiàn)原理Objective-C的+initialize方法調(diào)用原理分...
    RUNNING_NIUER閱讀 1,978評(píng)論 0 13
  • NSObject類中有兩個(gè)特殊方法:load、initialize陨溅,這兩個(gè)方法有什么區(qū)別呢终惑?如何使用呢?調(diào)用場(chǎng)景是...
    jeckHao閱讀 1,075評(píng)論 1 2
  • +load 與 +initialize 的異同 +load 方法會(huì)在 main() 函數(shù)之前調(diào)用门扇,而 +initi...
    NapoleonY閱讀 1,317評(píng)論 0 6
  • ??首先我們都知道在iOS應(yīng)用啟動(dòng)的時(shí)候會(huì)調(diào)用所有類和其分類的+load方法雹有。子類的load方法會(huì)在父類方法執(zhí)行完...
    _南山憶閱讀 1,532評(píng)論 1 1