class_addMethod

runtime版本objc4-723

class_addMethod申明于 runtime.h

OBJC_EXPORT BOOL
class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, 
                const char * _Nullable types) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

實現(xiàn)于objc-class-old.mm

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
{
    IMP old;
    if (!cls) return NO;

    old = _class_addMethod(cls, name, imp, types, NO);
    return !old;
}

這里調(diào)用了同個文件的static IMP _class_addMethod(Class cls, SEL name, IMP imp, const char *types, bool replace)函數(shù)董朝。該函數(shù)的主要功能是:

  • 判斷是否存在name對應的Method
    1. 若存在欲虚,則返回該Method的實現(xiàn)曼振;
    2. 若不存在栅受,則創(chuàng)建一個含有一個Methodold_method_list勿侯,將其地址插入methodLists所指數(shù)組,并返回nil抬闯。

該版本的struct objc_class中的methodLists成員是old_method_list **類型浑塞,而非objc_method_list **。申明于objc-runtime-old.h孕惜。

具體實現(xiàn)如下:

static IMP _class_addMethod(Class cls, SEL name, IMP imp, 
                            const char *types, bool replace)
{
    old_method *m;
    IMP result = nil;

    if (!types) types = "";

    mutex_locker_t lock(methodListLock);

    if ((m = _findMethodInClass(cls, name))) {
        // already exists
        // fixme atomic
        result = method_getImplementation((Method)m);
        if (replace) {
            method_setImplementation((Method)m, imp);
        }
    } else {
        // fixme could be faster
        old_method_list *mlist = 
            (old_method_list *)calloc(sizeof(old_method_list), 1);
        mlist->obsolete = fixed_up_method_list;
        mlist->method_count = 1;
        mlist->method_list[0].method_name = name;
        mlist->method_list[0].method_types = strdup(types);
        mlist->method_list[0].method_imp = imp;
        
        _objc_insertMethods(cls, mlist, nil);
        if (!(cls->info & CLS_CONSTRUCTING)) {
            flush_caches(cls, NO);
        } else {
            // in-construction class has no subclasses
            flush_cache(cls);
        }
        result = nil;
    }

    return result;
}

其中void _objc_insertMethods(Class cls, old_method_list *mlist, old_category *cat)實現(xiàn)在 objc-runtime-old.mm中愧薛。該函數(shù)的主要功能是:

  1. clsmethodLists為空,則將mlist賦予methodLists衫画,函數(shù)返回毫炉;
  2. 調(diào)用_objcTweakMethodListPointerForClass(cls),確保methodLists指向一個old_method_list數(shù)組削罩;
  3. methodLists所指數(shù)組已滿瞄勾,則將methodLists指向新的一個長度+1的數(shù)組费奸;
  4. methodLists所指數(shù)組的所有元素右移一個位;
  5. mlist賦予methodLists所指數(shù)組第一個元素进陡。

具體實現(xiàn)如下:

void _objc_insertMethods(Class cls, old_method_list *mlist, old_category *cat)
{
    old_method_list ***list;
    old_method_list **ptr;
    ptrdiff_t endIndex;
    size_t oldSize;
    size_t newSize;

    if (!cls->methodLists) {
        // cls has no methods - simply use this method list
        cls->methodLists = (old_method_list **)mlist;
        cls->setInfo(CLS_NO_METHOD_ARRAY);
        return;
    }

    // Log any existing methods being replaced
    if (PrintReplacedMethods) {
        int i;
        for (i = 0; i < mlist->method_count; i++) {
            extern IMP findIMPInClass(Class cls, SEL sel);
            SEL sel = sel_registerName((char *)mlist->method_list[i].method_name);
            IMP newImp = mlist->method_list[i].method_imp;
            IMP oldImp;

            if ((oldImp = findIMPInClass(cls, sel))) {
                logReplacedMethod(cls->name, sel, ISMETA(cls), 
                                  cat ? cat->category_name : nil, 
                                  oldImp, newImp);
            }
        }
    }

    // Create method list array if necessary
    _objcTweakMethodListPointerForClass(cls);
    
    list = &cls->methodLists;

    // Locate unused entry for insertion point
    ptr = *list;
    while ((*ptr != 0) && (*ptr != END_OF_METHODS_LIST))
        ptr += 1;

    // If array is full, add to it
    if (*ptr == END_OF_METHODS_LIST)
    {
        // Calculate old and new dimensions
        endIndex = ptr - *list;
        oldSize  = (endIndex + 1) * sizeof(void *);
        newSize  = oldSize + sizeof(old_method_list *); // only increase by 1

        // Grow the method list array by one.
        *list = (old_method_list **)realloc(*list, newSize);

        // Zero out addition part of new array
        bzero (&((*list)[endIndex]), newSize - oldSize);

        // Place new end marker
        (*list)[(newSize/sizeof(void *)) - 1] = END_OF_METHODS_LIST;

        // Insertion point corresponds to old array end
        ptr = &((*list)[endIndex]);
    }

    // Right shift existing entries by one
    bcopy (*list, (*list) + 1, (uint8_t *)ptr - (uint8_t *)*list);

    // Insert at method list at beginning of array
    **list = mlist;
}

static void _objcTweakMethodListPointerForClass(Class cls)的主要功能是:

  1. cls->methodLists有值愿阐,且cls->info不含有CLS_NO_METHOD_ARRAY,則函數(shù)返回趾疚;
  2. 創(chuàng)建一個長度為4的數(shù)組缨历;
  3. 將原來的cls->methodLists賦予數(shù)組第一個元素;
  4. END_OF_METHODS_LIST賦予數(shù)組最后一個元素糙麦;
  5. 將數(shù)組的地址賦予cls->methodLists辛孵;
  6. 取消cls->infoCLS_NO_METHOD_ARRAY標記。

具體實現(xiàn)如下:

static void _objcTweakMethodListPointerForClass(Class cls)
{
    old_method_list *   originalList;
    const int                   initialEntries = 4;
    size_t                          mallocSize;
    old_method_list **  ptr;

    // Do nothing if methodLists is already an array.
    if (cls->methodLists  &&  !(cls->info & CLS_NO_METHOD_ARRAY)) return;

    // Remember existing list
    originalList = (old_method_list *) cls->methodLists;

    // Allocate and zero a method list array
    mallocSize   = sizeof(old_method_list *) * initialEntries;
    ptr      = (old_method_list **) calloc(1, mallocSize);

    // Insert the existing list into the array
    ptr[initialEntries - 1] = END_OF_METHODS_LIST;
    ptr[0] = originalList;

    // Replace existing list with array
    cls->methodLists = ptr;
    cls->clearInfo(CLS_NO_METHOD_ARRAY);
}

Class的methodLists可能是:

  1. 空指針喳资,此時Class沒有方法七问,(info & CLS_NO_METHOD_ARRAY) == true沪饺。
  2. objc_method結(jié)構(gòu)體指針,此時Class有一個method_list。
  3. objc_method結(jié)構(gòu)體指針數(shù)組上祈,此時Class有多個method_list。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末廊镜,一起剝皮案震驚了整個濱河市即碗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搞疗,老刑警劉巖嗓蘑,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異匿乃,居然都是意外死亡桩皿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門幢炸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泄隔,“玉大人,你說我怎么就攤上這事宛徊》疰遥” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵闸天,是天一觀的道長暖呕。 經(jīng)常有香客問我,道長苞氮,這世上最難降的妖魔是什么湾揽? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上钝腺,老公的妹妹穿的比我還像新娘抛姑。我一直安慰自己,他們只是感情好艳狐,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布定硝。 她就那樣靜靜地躺著,像睡著了一般毫目。 火紅的嫁衣襯著肌膚如雪蔬啡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天镀虐,我揣著相機與錄音箱蟆,去河邊找鬼。 笑死刮便,一個胖子當著我的面吹牛空猜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播恨旱,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼辈毯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了搜贤?” 一聲冷哼從身側(cè)響起谆沃,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎仪芒,沒想到半個月后唁影,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡掂名,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年据沈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饺蔑。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡卓舵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出膀钠,到底是詐尸還是另有隱情,我是刑警寧澤裹虫,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布肿嘲,位于F島的核電站,受9級特大地震影響筑公,放射性物質(zhì)發(fā)生泄漏雳窟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望封救。 院中可真熱鬧拇涤,春花似錦、人聲如沸誉结。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惩坑。三九已至掉盅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間以舒,已是汗流浹背趾痘。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蔓钟,地道東北人永票。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像滥沫,于是被迫代替她去往敵國和親侣集。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉佣谐,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,709評論 0 9
  • 我們常常會聽說 Objective-C 是一門動態(tài)語言肚吏,那么這個「動態(tài)」表現(xiàn)在哪呢?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,192評論 0 7
  • //聯(lián)系人:石虎QQ: 1224614774昵稱:嗡嘛呢叭咪哄 objc_class結(jié)構(gòu)體 一狭魂、類在OC中是obj...
    石虎132閱讀 2,182評論 0 21
  • Objective-C語言是一門動態(tài)語言罚攀,它將很多靜態(tài)語言在編譯和鏈接時期做的事放到了運行時來處理。這種動態(tài)語言的...
    有一種再見叫青春閱讀 583評論 0 3
  • 原文出處:南峰子的技術(shù)博客 Objective-C語言是一門動態(tài)語言雌澄,它將很多靜態(tài)語言在編譯和鏈接時期做的事放到了...
    _燴面_閱讀 1,228評論 1 5