iOS category

category的實(shí)現(xiàn)原理

在上一篇文章iOS runtime中提到了class_rw_t這個(gè)結(jié)構(gòu)五慈,在category中的寫的方法蝎土,協(xié)議慨代,屬性等會在程序運(yùn)行經(jīng)由runtime寫入類的class_rw_t中息罗。這是怎么處理的呢疚鲤?

首先得看下category編譯后的結(jié)構(gòu)锥累。新建一個(gè)NSObject的category printCategory.使用clang命令行編譯出category的c++實(shí)現(xiàn)。

NSObject+printCategory.m文件如下

#import "NSObject+printCategory.h"


@implementation NSObject (printCategory)
+(void)printCategory{
    NSLog(@"category測試");
}
@end

clang命令行

clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk 分類的路徑

得出NSObject+printCategory.cpp文件,cpp文件中代碼較多集歇,抽取其中的關(guān)鍵代碼,我們編寫的category代碼最終幫我們生成了 struct _category_t類型的 _OBJC__CATEGORY_NSObject__printCategory的值

static struct /*_method_list_t*/ {
    unsigned int entsize;  // sizeof(struct _objc_method)
    unsigned int method_count;
    struct _objc_method method_list[1];
} _OBJC_$_CATEGORY_CLASS_METHODS_NSObject_$_printCategory __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_objc_method),
    1,
    {{(struct objc_selector *)"printCategory", "v16@0:8", (void *)_C_NSObject_printCategory_printCategory}}
};

static struct _category_t _OBJC_$_CATEGORY_NSObject_$_printCategory __attribute__ ((used, section ("__DATA,__objc_const"))) = 
{
    "NSObject",
    0, // &OBJC_CLASS_$_NSObject,
    0,
    (const struct _method_list_t *)&_OBJC_$_CATEGORY_CLASS_METHODS_NSObject_$_printCategory,
    0,
    0,
};

其中結(jié)構(gòu)體_category_t的定義如下

struct _category_t {
    const char *name;//被添加分類的類名稱
    struct _class_t *cls;
    const struct _method_list_t *instance_methods;//實(shí)例方法列表
    const struct _method_list_t *class_methods;//類方法列表
    const struct _protocol_list_t *protocols;//協(xié)議列表
    const struct _prop_list_t *properties;//屬性列表
};

在編譯過程中桶略,編譯器把category編譯成上面的內(nèi)容,然后運(yùn)行時(shí)候經(jīng)由runtime把_OBJC__CATEGORY_NSObject__printCategory里面的內(nèi)容合并到類信息class_rw_t這個(gè)結(jié)構(gòu)體中。

對于我們自定義的_OBJC__CATEGORY_NSObject__printCategory這個(gè)category际歼,會把class_methods里面的值惶翻,也就是OBJC_CATEGORY_CLASS_METHODS_NSObject__printCategory結(jié)構(gòu)題里面的方法列表粗井,合并到類信息class_rw_t中搜锰,大概的流程圖如下

QQ20200524-190258.png

class_rw_t 中的method_lists是一個(gè)二維數(shù)組,對于數(shù)組的每一行彬檀,存儲一個(gè)文件里面的方法列表巴帮。如類的原有方法列表會存儲到一個(gè)一維數(shù)組里面溯泣,printCategory這個(gè)category里面的方法會存儲到另外一個(gè)一維數(shù)組里面。
當(dāng)把分類的方法合并到method_lists里面時(shí)候榕茧,往method_lists里面插入一個(gè)分類的方法的數(shù)組垃沦。

runtime在合并category的方法列表的時(shí)候,會把類所有的category編譯出來的方法數(shù)組加載出來用押,統(tǒng)計(jì)一共有多少個(gè)一維數(shù)組肢簿,假設(shè)一維數(shù)組的數(shù)量為n,然后把類原有的方法數(shù)組往后挪動n位。再把category里面的方法數(shù)組拷貝到method_lists數(shù)組里面蜻拨。對于拷貝的順序池充,越往后編譯的category方法數(shù)組列表越靠前。

如下圖中NSObject有兩個(gè)category, printCategory 和 printCategory2缎讼。


[圖片上傳中...(QQ20200524-191721.png-b59d76-1590319063271-0)]

printCategory排在printCategory2前面收夸,在method_lists列表中數(shù)組的順序printCategory的方法數(shù)組列表比printCategory2的靠前。


QQ20200524-191721.png

當(dāng)我們調(diào)用NSObject 的printCategory方法的時(shí)候血崭,會去method_lists從前往后遍歷查找方法卧惜。當(dāng)在printCategory的分類方法數(shù)組中找到printCategory方法時(shí),會停止查找方法夹纫,并把剛才找到的方法放到類的方法緩存中咽瓷,并執(zhí)行方法。所以即便printCategory2分類中也存在printCategory方法舰讹,也不會執(zhí)行到茅姜。

如果分類中存在與類原有的相同的方法,分類中的方法會“覆蓋”掉類原有的方法月匣。如果有多個(gè)分類中存在同一個(gè)方法匈睁,調(diào)用時(shí)執(zhí)行最后編譯的分類方法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末桶错,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子胀蛮,更是在濱河造成了極大的恐慌院刁,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粪狼,死亡現(xiàn)場離奇詭異退腥,居然都是意外死亡任岸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門狡刘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來享潜,“玉大人,你說我怎么就攤上這事嗅蔬〗0矗” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵澜术,是天一觀的道長艺蝴。 經(jīng)常有香客問我,道長鸟废,這世上最難降的妖魔是什么猜敢? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮盒延,結(jié)果婚禮上缩擂,老公的妹妹穿的比我還像新娘。我一直安慰自己添寺,他們只是感情好胯盯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著畦贸,像睡著了一般陨闹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上薄坏,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天趋厉,我揣著相機(jī)與錄音,去河邊找鬼胶坠。 笑死君账,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沈善。 我是一名探鬼主播乡数,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼闻牡!你這毒婦竟也來了净赴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤罩润,失蹤者是張志新(化名)和其女友劉穎玖翅,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡金度,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年应媚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片猜极。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡中姜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出跟伏,到底是詐尸還是另有隱情丢胚,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布酬姆,位于F島的核電站嗜桌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辞色。R本人自食惡果不足惜骨宠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望相满。 院中可真熱鬧层亿,春花似錦、人聲如沸立美。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽建蹄。三九已至碌更,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間洞慎,已是汗流浹背痛单。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劲腿,地道東北人旭绒。 一個(gè)月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像焦人,于是被迫代替她去往敵國和親挥吵。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355