iOS Runtime之消息傳遞

先上一張經(jīng)典圖:


messageSend.png

一悠咱、通過上圖我們可以得到幾個(gè)關(guān)鍵詞:(Instance of Subclass)實(shí)例對(duì)象、(class)類對(duì)象、(meta)元類埠胖。

并有如下結(jié)論:
1、實(shí)例對(duì)象的isa指針指向其所屬的class類淳玩,這個(gè)類本質(zhì)也是一個(gè)對(duì)象直撤,即類對(duì)象。
2蜕着、類對(duì)象的isa指針指向meta元類谋竖。
3、繼承樹上所有元類的isa指針都指向根類(一般是NSObject)的元類承匣。
4蓖乘、根類的元類的isa指針指向自己。
5韧骗、根類的元類的父類是根類本身嘉抒,形成了一個(gè)閉環(huán)
6、根類的父類是nil袍暴。

二些侍、

先定義幾個(gè)變量

Son *s = [Son new];
Class metaSon = objc_getMetaClass("Son");

上面代碼中s是實(shí)例對(duì)象隶症、Son是類(類對(duì)象)、metaSon是元類岗宣。

我們先通過category給NSObject增加一個(gè)實(shí)例方法- (void)eat和一個(gè)類方法+ (void)eat蚂会。

值得注意的是

- (void)eat是添加在類對(duì)象NSObject的方法列表中的,

+ (void)eat則是添加在NSObject的元類的方法列表中的狈定。

通過category添加的方法會(huì)在Runtime時(shí)動(dòng)態(tài)添加在類的方法列表的最前端颂龙,消息傳遞時(shí)會(huì)先執(zhí)行category添加的方法然后return,造成添加了相同名字的方法會(huì)覆蓋掉原來的方法的假象纽什,其實(shí)原來的方法還存在于方法列表中措嵌,只是位置靠后,被靠前的同名方法攔截了芦缰。

@interface NSObject (LiLi)

+ (void)eat;
- (void)eat;

@end

@implementation NSObject (LiLi)

- (void)eat
{
    NSLog(@"lili eat shit");
}

+ (void)eat
{
    NSLog(@"lili eat shit plus");
}

@end

Father類繼承于NSObject企巢,并重寫了- (void)eat方法;

@interface Father : NSObject

@end

@implementation Father

- (void)eat
{
    NSLog(@"father eat food");
}

@end

Son類繼承于Father让蕾。

@interface Son : Father

@end

@implementation Son

@end

下面分析如下代碼會(huì)輸出什么

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    Son *s = [Son new];
    [s eat];
    }
@end

消息傳遞通過Runtime實(shí)現(xiàn)浪规,[s eat]在運(yùn)行時(shí)會(huì)轉(zhuǎn)換為objc_msgSend(s,eat),執(zhí)行流程為:
1探孝、通過s的isa指針找到其所屬的類即Son笋婿,然后在Son的方法列表中查找eat方法,如果找到eat則執(zhí)行顿颅,否則進(jìn)行第二步缸濒。
2、通過Son的super_class指針找到其父類Father粱腻,然后在Father的方法列表中查找eat方法庇配,如果找到eat則執(zhí)行,否則沿著其繼承樹一直向上查找绍些。
3捞慌、如果一直查找到根類(一般為NSObject)還是沒有查找到eat方法,則進(jìn)入消息轉(zhuǎn)發(fā)流程柬批,后面會(huì)介紹消息轉(zhuǎn)發(fā)的三次機(jī)會(huì)啸澡。

在上例中NSObject通過category添加了實(shí)例方法- (void)eat,F(xiàn)ather類中重寫了- (void)eat方法氮帐,而Son類中無任何實(shí)現(xiàn)锻霎。

所以根據(jù)上述消息傳遞過程,會(huì)打印出Father類里重寫的eat方法:

father eat food

如果Son類中重寫了eat方法則會(huì)執(zhí)行Son類里的eat方法揪漩,如果Son類和Father類都沒有重寫eat方法,則執(zhí)行NSObject (LiLi)里的eat方法吏口。

再看如下代碼奄容,同樣的分類增加兩個(gè)方法,其中+ (void)eat只有聲明冰更,沒有實(shí)現(xiàn)。

@interface NSObject (LiLi)

+ (void)eat;
- (void)eat;

@end

@implementation NSObject (LiLi)

- (void)eat
{
    NSLog(@"lili eat shit");
}

@end

Father類繼承于NSObject

@interface Father : NSObject

@end

@implementation Father

@end

Son類繼承于Father昂勒。

@interface Son : Father

@end

@implementation Son

@end

下面分析如下代碼會(huì)輸出什么蜀细?

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    Class metaSon = objc_getMetaClass("Son");
    [Son eat];
    }
@end

我們執(zhí)行的是+ (void)eat類方法,消息傳遞時(shí)卻執(zhí)行了實(shí)例方法- (void)eat戈盈,故打印如下:

lili eat shit

分析如下:
類方法+ (void)eat的消息傳遞流程類似于上述流程奠衔,特殊的地方在于NSObject的元類的父類是NSObject本身,我們前面第5點(diǎn)結(jié)論說過NSObject和NSObject的元類形成了一個(gè)閉環(huán)塘娶,所以NSObject的類方法在此處可以傳遞到NSObject的實(shí)例方法上归斤。

Runtime時(shí) [Son eat]在運(yùn)行時(shí)會(huì)轉(zhuǎn)換為objc_msgSend(Son,eat),搜索的是繼承樹上所有元類的方法列表:
1刁岸、通過Son的isa指針找到其所屬的元類即metaSon脏里,然后在metaSon的方法列表中查找+ (void)eat方法,如果找到+ (void)eat則執(zhí)行虹曙,否則進(jìn)行第二步迫横。
2、通過metaSon的super_class指針找到其父類即Father的元類酝碳,然后在Father的元類方法列表中查找+ (void)eat方法矾踱,如果找到+ (void)eat則執(zhí)行,否則沿著其繼承樹一直向上查找疏哗。
3呛讲、如果一直查找到根類(NSObject的元類)還是沒有查找到+(void)eat方法,則會(huì)去NSObject的元類的父類(即NSObject本身)中查找實(shí)例方法- (void)eat沃斤,此處類方法傳遞為實(shí)例方法圣蝎,還是比較特殊的。

以上衡瓶。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末徘公,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子哮针,更是在濱河造成了極大的恐慌关面,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件十厢,死亡現(xiàn)場(chǎng)離奇詭異等太,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蛮放,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門缩抡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人包颁,你說我怎么就攤上這事瞻想⊙拐妫” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵蘑险,是天一觀的道長(zhǎng)滴肿。 經(jīng)常有香客問我,道長(zhǎng)佃迄,這世上最難降的妖魔是什么泼差? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮呵俏,結(jié)果婚禮上堆缘,老公的妹妹穿的比我還像新娘。我一直安慰自己柴信,他們只是感情好套啤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著随常,像睡著了一般潜沦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绪氛,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天唆鸡,我揣著相機(jī)與錄音,去河邊找鬼枣察。 笑死争占,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的序目。 我是一名探鬼主播臂痕,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼猿涨!你這毒婦竟也來了握童?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤叛赚,失蹤者是張志新(化名)和其女友劉穎澡绩,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俺附,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肥卡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了事镣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片步鉴。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出唠叛,到底是詐尸還是另有隱情只嚣,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布艺沼,位于F島的核電站,受9級(jí)特大地震影響蕴掏,放射性物質(zhì)發(fā)生泄漏障般。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一盛杰、第九天 我趴在偏房一處隱蔽的房頂上張望挽荡。 院中可真熱鬧,春花似錦即供、人聲如沸定拟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽青自。三九已至,卻和暖如春驱证,著一層夾襖步出監(jiān)牢的瞬間延窜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國打工抹锄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逆瑞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓伙单,卻偏偏與公主長(zhǎng)得像获高,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吻育,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353