消息轉發(fā)機制(Effective Objective-C摘錄學習篇)

對象在收到無法解讀的消息之后會發(fā)生什么情況

消息轉發(fā)分為兩大階段坦刀。第一階段先征詢接收者,所屬的的類沐寺,看其是否能動態(tài)添加方法混坞,以處理當前這個“未知的選擇子”究孕,這叫做“動態(tài)方法解析”厨诸。第二階段涉及“完整的的消息轉發(fā)機制”。這又細分為兩小步禾酱。首先微酬,請接收者看看有沒有其它對象能處理這條消息。若有颤陶,則運行期系統(tǒng)會把消息轉給那個對象得封,于是消息轉發(fā)過程結束,一切如常指郁。若沒有“備援接收者”則啟動完整的消息轉發(fā)機制忙上,運行期系統(tǒng)會把與消息有關的全部細節(jié)都封裝到NSInvocation對象中,再給接收者最后一次機會闲坎,令其設法解決當前還未處理的這條消息疫粥。

動態(tài)方法解析

對象在收到無法解讀的消息后,首先將調用其所屬類的下列類方法

+ (Bool)resolveInstanceMethod:(SEL)selector

該方法的參數(shù)就是那個未知的選擇子腰懂,其返回值為Boolean類型梗逮,表示這個類是否能新增一個實例方法用以處理此選擇子。假如尚未實現(xiàn)的方法不是實例方法而是類方法绣溜,那么運行期系統(tǒng)就會調用另外一個方法,該方法與“resolveInstanceMethod:”類似跋选,叫做“resolveClassMethod:”
使用這種方法的前提是:相關方法的實現(xiàn)代碼已經寫好,只等著運行的時候動態(tài)插在類里面就可以了只搁。此方案常用來實現(xiàn)@dynamic屬性。

備援接收者

當前接收者還有第二次機會能處理未知的選擇子缭付,在這一步中的妖,運行期系統(tǒng)會問它:能不能把這條消息轉發(fā)給其它接收者來處理。與該步驟對應的處理方法如下:

- (id)forwardingTargetForSelector:(SEL)selector

方法參數(shù)代表未知的選擇子,若當前接收者能找到備援對象平夜,則將其返回兼贸,若找不到,就返回nil颜及。我們可以用“組合”來模擬出“多重繼承”的某些特性痊土。在一個對象內部,可能還有一系列其它對象衡载,該對象可經由此方法將能夠處理某選擇子的相關對象返回菩收,這樣的話,在外界看來拴念,好像是該對象親自處理了這些消息似的公般。

完整的消息轉發(fā)

如果轉發(fā)算法已經來到這一步的話刽虹,那么唯一能做的就是啟用完整的消息轉發(fā)機制了。首先創(chuàng)創(chuàng)建NSInvocation對象,把與尚未處理的那條消息有關的全部細節(jié)都封裝于其中。此對象包含選擇子、目標及參數(shù)。在觸發(fā)NSInvocation對象時拢锹,“消息派發(fā)系統(tǒng)”將親自出馬,把消息指派給目標對象。
此步驟會調用下列方法來轉發(fā)消息:
- (void)forwardInvocation:(NSInvocation *)invocation
實現(xiàn)此方法時,若發(fā)現(xiàn)調用操作不應由本類來處理巡莹,則需要調用超類的同名方法。這樣的話额嘿,繼承體系中的每個類都有機會處理此調用請求捕儒,直至NSObject。如果最后調用了NSObject的方法阎毅,那么該方法還會繼而調用“doesNotRecognizeSelector:”以拋出異常扇调,此異常表明選擇子最終未能得到處理熬芜。

完整的例子演示動態(tài)方法解析

以動態(tài)方法解析@dynamic屬性鼓拧,類自動處理相關屬性的存放與獲取操作(編寫一個類似“字典”的對象)

@interface EOCAutoDictionary : NSObject

@property (nonatomic, strong) NSString *string;
@property (nonatomic, strong) NSNumber *number;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) id opaqueObject;

@end
//需要引入頭文件#import <objc/runtime.h>
@interface EOCAutoDictionary ()

@property (nonatomic, strong) NSMutableDictionary *backingStore;

@end

@implementation EOCAutoDictionary

@dynamic string, number, date, opaqueObject;

- (instancetype)init {
    if (self = [super init]) {
        _backingStore = [NSMutableDictionary new];
    }
    return self;
}


id autoDictionaryGetter(id self, SEL _cmd) {
    EOCAutoDictionary *typedSelf = (EOCAutoDictionary *)self;
    NSMutableDictionary *backingStore = typedSelf.backingStore;
    NSString *key = NSStringFromSelector(_cmd);
    return [backingStore objectForKey:key];
}

void autoDictionarySetter(id self, SEL _cmd, id value) {
    EOCAutoDictionary *typedSelf = (EOCAutoDictionary *)self;
    NSMutableDictionary *backingStore = typedSelf.backingStore;
    NSString *selectorString = NSStringFromSelector(_cmd);
    NSMutableString *key = [selectorString mutableCopy];
    [key deleteCharactersInRange:NSMakeRange(key.length - 1, 1)];
    [key deleteCharactersInRange:NSMakeRange(0, 3)];
    NSString *lowercaseFirstChar = [[key substringToIndex:1] lowercaseString];
    [key replaceCharactersInRange:NSMakeRange(0, 1) withString:lowercaseFirstChar];
    if (value) {
        [backingStore setObject:value forKey:key];
    } else {
        [backingStore removeObjectForKey:key];
    }
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSString *selectorString = NSStringFromSelector(sel);
    if ([selectorString hasPrefix:@"set"]) {
        class_addMethod(self, sel, (IMP)autoDictionarySetter, "v@:@");
    } else {
        class_addMethod(self, sel, (IMP)autoDictionaryGetter, "@@:");
    }
    return YES;
}

@end
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末怒炸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子毡代,更是在濱河造成了極大的恐慌阅羹,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件教寂,死亡現(xiàn)場離奇詭異捏鱼,居然都是意外死亡,警方通過查閱死者的電腦和手機酪耕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門导梆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人迂烁,你說我怎么就攤上這事看尼。” “怎么了盟步?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵藏斩,是天一觀的道長。 經常有香客問我址芯,道長灾茁,這世上最難降的妖魔是什么窜觉? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任谷炸,我火速辦了婚禮,結果婚禮上禀挫,老公的妹妹穿的比我還像新娘旬陡。我一直安慰自己,他們只是感情好语婴,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布描孟。 她就那樣靜靜地躺著,像睡著了一般砰左。 火紅的嫁衣襯著肌膚如雪匿醒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天缠导,我揣著相機與錄音廉羔,去河邊找鬼。 笑死僻造,一個胖子當著我的面吹牛憋他,可吹牛的內容都是我干的孩饼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼竹挡,長吁一口氣:“原來是場噩夢啊……” “哼镀娶!你這毒婦竟也來了?” 一聲冷哼從身側響起揪罕,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤梯码,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后好啰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忍些,經...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年坎怪,在試婚紗的時候發(fā)現(xiàn)自己被綠了罢坝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡搅窿,死狀恐怖嘁酿,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情男应,我是刑警寧澤闹司,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站沐飘,受9級特大地震影響游桩,放射性物質發(fā)生泄漏。R本人自食惡果不足惜耐朴,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一借卧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧筛峭,春花似錦铐刘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至挂签,卻和暖如春疤祭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饵婆。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工勺馆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓谓传,卻偏偏與公主長得像蜈项,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子续挟,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內容