iOS開發-消息轉發

jopen 8年前發布 | 6K 次閱讀 iOS開發 程序員 移動開發

消息轉發是OC運行時比較重要的特性,Objective-C運行時的主要的任務是負責消息分發,我們在開發中 " unrecognized selector sent to instance xx",實例對象沒有實現對應的消息,通常我們只需要實現未實現的方法即可。一般情況我們處理一個方法,運行時尋找匹配的selector然后執行,但是有時候只想在運行時才創建某個方法,消息確沒有具體的實現,這個時候就會出出現運行時錯誤,按照消息轉發的順序我們有三種解決辦法。

動態方法處理

首先我們來看一個簡單的例子,定義一個Message類,定義一個responseMethod方法,不實現方法,直接調用:

Message  *msg=[[Message alloc]init];
        [msg responseMethod];

錯誤信息如下:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Message responseMethod]: unrecognized selector sent to instance 0x10011ad20'

動態方法的重寫有兩個可以調用方法:

+ (BOOL)resolveClassMethod:(SEL)sel OSX_AVAILABLE_STARTING(MAC_10_5, __IPHONE_2_0);

} +(BOOL)resolveClassMethod:(SEL)sel{ return [super resolveClassMethod:sel]; }</pre>

動態執行的函數:

void dynamicMethodIMP(id self, SEL _cmd)
{
    NSLog(@"Developer--dynamicMethodIMP--%@",NSStringFromSelector(_cmd));
}

消息轉發

如果上面的方法沒有重寫或者說是返回NO,那么我們接下來的按照順序還有兩種選擇,兩種選擇的原理都是一樣,消息有對應的target,我們需要更換對應的target即可:

- (id)forwardingTargetForSelector:(SEL)aSelector __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
forwardingTargetForSelector返回參數是一個對象,如果對象非nil、非self,系統會將運行的消息轉發給這個對象執行,否則會執行第三種解決方案。
-(id)forwardingTargetForSelector:(SEL)aSelector{
    NSLog(@"FlyElephant-http://www.cnblogs.com/xiaofeixiang/");
    NSLog(@"forwardingTargetForSelector");
    if (aSelector==@selector(responseMethod)) {
         return developer;
    }
    return self;
}

第二種消息是將消息發送到另外一個對象,如果想要修改消息,那么就要使用 -forwardInvocation: ,運行時將消息打包成NSInvocation,然后返回給你處理。處 理完之后,調用 i nvokeWithTarget,但是如果是是調用-forwardInvocation是無法執行成功,在執行之前我們進行方法簽名。

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    NSLog(@"methodSignatureForSelector");
    if ([super respondsToSelector:aSelector]) {
        return   [super methodSignatureForSelector:aSelector];
    }else{
        return  [developer methodSignatureForSelector:aSelector];
    }
}

-(void)forwardInvocation:(NSInvocation *)anInvocation{ NSLog(@"forwardInvocation"); SEL sel=[anInvocation selector]; if ([developer respondsToSelector:sel]) { [anInvocation invokeWithTarget:developer]; }else{ [super forwardInvocation:anInvocation]; } }</pre>

關于Developer類中的方法:

@implementation Developer

-(void)responseMethod{ NSLog(@"博客園:FlyElephant-

@end</pre>

Cocoa中代理(Proxies)和響應鏈(Responder Chain)用到了消息轉發。NSProxy是一個輕量級的class,它的作用就是轉發消息到另一個object。如果想要惰性加載object的某個屬性會很有用。NSUndoManager也有用到,不過是截取消息,之后再執行,而不是轉發到其他的地方。                                    

響應鏈是關于Cocoa如何處理與發送事件與行為到對應的對象,通常我們處理的鍵盤文本框事件 First Responder,如果沒有處理該消息,則轉發到下一個 -nextResponder 。這么一直下去直到找到能夠處理該消息的object,或者沒有找到,報錯。

</div>

來自: http://www.cnblogs.com/xiaofeixiang/p/5095023.html

</span>

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!