首先疚察,該方法在調用時,系統(tǒng)會查看這個對象能否接收這個消息(查看這個類有沒有這個方法宾袜,或者有沒有實現(xiàn)這個方法捻艳。),如果不能并且只在不能的情況下庆猫,就會調用下面這幾個方法认轨,給你“補救”的機會,你可以先理解為幾套防止程序crash的備選方案月培,我們就是利用這幾個方案進行消息轉發(fā)好渠,注意一點,前一套方案實現(xiàn)后一套方法就不會執(zhí)行节视。如果這幾套方案你都沒有做處理拳锚,那么程序就會報錯crash。
打個比方:比賽足球時寻行,腳下有球的那名球員霍掺,如果他的位置不利于射門或者他的球即將被對方球員搶斷,這時最好是把球傳出去,這里的球就相當于消息杆烁。
方案一:
+ (BOOL)resolveInstanceMethod:(SEL)sel
+ (BOOL)resolveClassMethod:(SEL)sel
方案二:
- (id)forwardingTargetForSelector:(SEL)aSelector
方案三:
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;
到目前為止大家已經(jīng)知道什么是消息轉發(fā)了牙丽。下面就說一下這幾套方案是怎樣調用的。
首先兔魂,系統(tǒng)會調用resolveInstanceMethod(當然烤芦,如果這個方法是一個類方法,就會調用resolveClassMethod)讓你自己為這個方法增加實現(xiàn)析校。
咱們來看一個例子:
首先构罗,創(chuàng)建了一個Person類的對象p,然后調用p的run方法智玻,注意遂唧,這個run方法是沒有寫實現(xiàn)的。
進入Person類的.m文件吊奢,我實現(xiàn)了resolveInstanceMethod這個方法為我的Person類動態(tài)增加了一個run方法的實現(xiàn)盖彭。(什么是動態(tài)增加?其實就是在程序運行的時候給某類的某個方法增加實現(xiàn)页滚。具體實現(xiàn)內(nèi)容就為上面的void run 這個c函數(shù)召边。)
當外部調用[p run]時,由于我們沒有實現(xiàn)run對應的方法裹驰,那么系統(tǒng)會調用resolveInstanceMethod讓你去做一些其他操作掌实。(當然,你也可以不做操作邦马,只是在這個例子中贱鼻,我為run方法動態(tài)增加了實現(xiàn)。)
繼續(xù)運行滋将,程序走到了我們C函數(shù)的部分邻悬,這樣程序沒有了崩潰。
下面講一下第二套方法随闽,forwardingTargetForSelector父丰,這個方法返回你需要轉發(fā)消息的對象。
我們接著這個例子來講掘宪,為了便于演示消息轉發(fā)蛾扇,我們新建了一個汽車類Car,并且實現(xiàn)了Car的run方法魏滚。
現(xiàn)在我不去對方案一的resolveInstanceMethod做任何處理镀首,直接調用父類方法∈蟠危可以看到更哄,系統(tǒng)已經(jīng)來到了forwardingTargetForSelector方法芋齿,我們現(xiàn)在返回一個Car類的實例對象。
繼續(xù)運行成翩,程序就來到了Car類的run方法觅捆,這樣,我們就實現(xiàn)了消息轉發(fā)麻敌。
繼續(xù)我們的例子栅炒。如果我們不實現(xiàn)forwardingTargetForSelector,系統(tǒng)就會調用方案三的兩個方法methodSignatureForSelector和forwardInvocation
methodSignatureForSelector用來生成方法簽名术羔,這個簽名就是給forwardInvocation中的參數(shù)NSInvocation調用的赢赊。
開頭我們要找的錯誤unrecognized selector sent to instance原因,原來就是因為methodSignatureForSelector這個方法中聂示,由于沒有找到run對應的實現(xiàn)方法,所以返回了一個空的方法簽名簇秒,最終導致程序報錯崩潰鱼喉。
所以我們需要做的是自己新建方法簽名,再在forwardInvocation中用你要轉發(fā)的那個對象調用這個對應的簽名趋观,這樣也實現(xiàn)了消息轉發(fā)扛禽。
關于生成簽名的類型"v@:"解釋一下。每一個方法會默認隱藏兩個參數(shù)皱坛,self编曼、_cmd,self代表方法調用者剩辟,_cmd代表這個方法的SEL掐场,簽名類型就是用來描述這個方法的返回值、參數(shù)的贩猎,v代表返回值為void熊户,@表示self,:表示_cmd吭服。