這是Effective Objective-C 2.0 的第12條
消息傳遞
我們先簡單講一下消息傳遞的過程。
當(dāng)我們向某個對象(接收者)傳遞一個消息,在運行時匆篓,會先去這個對象的所屬類中進行方法匹配揖赴,首先去cache列表中查找诡延,如果沒有,再去方法列表中查找忙菠,找到了調(diào)用何鸡,若找不到,則去父類方法列表中查找牛欢,一直向上找骡男,期間如果可以匹配成功,則調(diào)用方法傍睹,并將其緩存到對象所屬類的cache列表中隔盛,以方便下次查找犹菱,如果一直找不到,那就會進行“消息轉(zhuǎn)發(fā)”吮炕。那么消息轉(zhuǎn)發(fā)是如何進行的呢腊脱?
消息轉(zhuǎn)發(fā)
其實,在一開始龙亲,并不會去轉(zhuǎn)發(fā)陕凹,而是會進行一次詢問
“喂,小鬼鳄炉,再給你一次機會杜耙,要不要現(xiàn)在添加方法?”
“現(xiàn)在拂盯?運行時泥技?可以這么做么?”
當(dāng)讓可以磕仅,這就是OC語言的強大之處珊豹,可以動態(tài)添加方法。怎么做呢榕订?
首先店茶,我們先準備好一個函數(shù),這個函數(shù)就可以認為是給消息的一個實現(xiàn)劫恒。
接著在所屬類中實現(xiàn)這么一個方法
這個方法是干嘛的贩幻?這個方法其實就是對接受者所屬類的詢問,在其內(nèi)部通過class_addMethod這個函數(shù)两嘴,向當(dāng)前類提供消息的實現(xiàn)丛楚,這個函數(shù)的原型如下
BOOL class_addMethod(Class cls, SEL name, IMP imp,const char *types)
OK,這樣我們就動態(tài)的添加了一個方法實現(xiàn)憔辫,運行成功趣些,cool!這邊我們要注意的是,如果接受是類贰您,會通過resolveClassMethod:方法進行訊問坏平。
倘若我們沒有實現(xiàn)這個方法,那會怎樣呢锦亦?
“小鬼舶替,那你看看有沒有人可以幫你做這個事情?”
“案茉啊顾瞪?找人幫忙啊!”
“有的話陈醒,我就把這個消息發(fā)給他惕橙。”
是的孵延,此時會再次訊問接受者,有沒有其他對象可以執(zhí)行這個操作亲配,若有尘应,則進行消息轉(zhuǎn)發(fā)。那如何訊問呢吼虎?是通過下面這個方法
- (id)forwardingTargetForSelector:(SEL)aSelector
我們需要返回一個對象犬钢,這個對象就是轉(zhuǎn)發(fā)后的消息接受者,如:
此時Animal對象就成為了消息接受者思灰。
好了玷犹,如果到了這一步還是沒有任何作為的話,就會進行最后一步了
“小鬼洒疚,給你最后一次幾回歹颓,我把所有消息相關(guān)的細節(jié)全部封裝在一個對象中,你去最后想辦法處理一下吧油湖?”
此時巍扛,運行時系統(tǒng)會將所有的細節(jié)(消息、目標)封裝一個NSInvocation對象中乏德,我們可以修改一些細節(jié)撤奸,是其做一些處理。比如我們依然可以在這個時候修改消息接收者喊括,類似于上面的操作
我們在此時調(diào)用來方法胧瓜,但改變了方法的執(zhí)行的目標。這個方法我們要注意一個細節(jié)郑什,要想改變目標執(zhí)行這個方法府喳,我們需要先注冊一下這個消息的類型
好了,基本整個消息轉(zhuǎn)發(fā)的流程就到此結(jié)束了蘑拯。對于forwardInvocation:這個方法劫拢,如果發(fā)現(xiàn)依然做不了事情,會去調(diào)用父類的此方法强胰,一直到NSObject,如果到了NSObject,該方法會調(diào)用doesNotRecognizedSelector:方法舱沧,拋出異常。
上面的這些方法偶洋,我們除了可以捕獲轉(zhuǎn)發(fā)流程熟吏,其實我們也可以利用著做一些其他的事情,比如說實現(xiàn)@dynamic屬性的方法,實現(xiàn)多重繼承等功能牵寺,這些有機會再聊悍引。