使用NSMethodSignature和NSInvocation實現訊息轉寄

來源:互聯網
上載者:User

參考:

[1]http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html

[2]http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1

[3]http://theocacao.com/document.page/264/

[4]http://blog.sina.com.cn/s/blog_605409770100nib5.html

NSMethodSignature顧名思義應該就是“方法簽名”,類似於C++中的編譯器對函數進行簽名。從這裡可以發現,其他很多語言的很多東西都是類似的。官方定義該類為對方法的參數、返回類似進行封裝,協同NSInvocation實現訊息轉寄。(Class encapsulating
type information for method arguments and return value. It is used as a component of NSInvocation to
implement message forwarding。)NSInvocation主要用於不同對象間的訊息轉寄。

首先、什麼是訊息轉寄?

我們知道objective-c中調用方法的方式是發訊息,那如果給一個執行個體對象發一個未定義的訊息呢?結果就是crash,其實這中間系統給我們第二次機會,就是可以轉寄該訊息。

@interface classA : NSObject {}- (void)classAMethodOne;@end@interface classB : NSObject {    classA*   classa_;}@end

如上述代碼所示,如果建立classB類的執行個體對象instanceB,然後發送[instanceB classAMethodOne]訊息,那麼就會crash。crash是因為如果objective-c runtime 在運行時動態決議該方法時,resolveClassMethod,不能決議,就是找不到。然後runtime會給該執行個體第二次機會,首先調用methodSignatureForSelector 或去方法簽名,然後調用forwardInvocation,如果使用者自己定義的類,沒有重寫這兩個方法,即不支援方法轉寄,那麼就會調用父類NSObject的方法。NSObject父類方法forwardInvocation
中如下所示,所以導致異常,crash。

- (void) forwardInvocation: (NSInvocation*)anInvocation{  [self doesNotRecognizeSelector:[anInvocation selector]];  return;}- (void) doesNotRecognizeSelector: (SEL)aSelector{  [NSException raise: NSInvalidArgumentException       format: @"%s does not recognize %s",       object_get_class_name(self), sel_get_name(aSelector)];}

雖然classB不能響應訊息,但classB的成員classa_卻能響應該訊息。因此,通過將該訊息轉寄給成員classa_即可實現[instanceB classAMethodOne]正常運行。這時,其實也提供了一個Objective-C不支援多重繼承的解決方案,通過訊息轉寄,實現classB也能響應ClassA的方法。

其次、如何?訊息轉寄?

@interface LOCBird : NSObject {NSString* name_;    }@end@implementation LOCBird- (id)init{self = [super init];if (self) {name_ = [[NSString alloc] initWithString:@"I am a Bird!!"];}return self;}- (void)dealloc{[name_release];[super dealloc];}- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];if (signature==nil) {signature = [name_ methodSignatureForSelector:aSelector];}NSUInteger argCount = [signature numberOfArguments];for (NSInteger i=0 ; i<argCount ; i++) {NSLog(@"%s" , [signature getArgumentTypeAtIndex:i]);}NSLog(@"returnType:%s ,returnLen:%d" , [signature methodReturnType] , [signature methodReturnLength]);NSLog(@"signature:%@" , signature);return signature;}- (void)forwardInvocation:(NSInvocation *)anInvocation{NSLog(@"forwardInvocation:%@" , anInvocation);SEL seletor = [anInvocation selector];if ([name_ respondsToSelector:seletor]) {[anInvocation invokeWithTarget:name_];}}@end

如上所示,實現訊息轉寄只需重載NSobject的兩個方法,methodSignatureForSelector和forwardInvocation即可實現訊息的轉寄,為了防止轉寄訊息時出錯,可以調用respondsToSelector判斷能否響應對應的訊息。

id bird = [[LOCBird alloc] init];NSLog(@"len= %d", [bird length]);

運行結果如下,其中 @表示對象,:表示a method selector ,具體見參考[2],這兩個預設參數就是隱藏的self  和_cmd參數。

2012-03-21 23:40:54.488 LOCMessageForward[1003:207] 0xf263cc

2012-03-21 23:40:54.489 LOCMessageForward[1003:207] @

2012-03-21 23:40:54.491 LOCMessageForward[1003:207] :

2012-03-21 23:40:54.492 LOCMessageForward[1003:207] returnType:I ,returnLen:4

2012-03-21 23:40:54.493 LOCMessageForward[1003:207] signature:<NSMethodSignature: 0x4d255d0>

2012-03-21 23:40:54.493 LOCMessageForward[1003:207] forwardInvocation:<NSInvocation: 0x4d25960>

2012-03-21 23:40:54.495 LOCMessageForward[1003:207] len= 13


一個更簡單實現訊息轉寄的方法是只 重載forwardingTargetForSelector方法。

- (id)forwardingTargetForSelector:(SEL)aSelector{NSLog(@"forwardingTargetForSelector");if ([name_ respondsToSelector:aSelector]) {return name_;}return nil;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.