今天忽然又興趣看了下 NSObject的頭文件,發現其中的消息轉發機制還不甚瞭解,因此在 debug 調試瞭解以後,寫下此文章留做記錄 函數
- (id)forwardingTargetForSelector:(SEL)aSelector; - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector; + (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector; - (void)forwardInvocation:(NSInvocation *)anInvocation; - (void)doesNotRecognizeSelector:(SEL)aSelector;調用順序如上面函數順序
當使用以下函數調用 spa
[someObj method1];//方式1 [someObj performSelector:@selector(method1)];//方式2若是 someObj沒有實現 method1函數
runtime 將會調用 debug
- (id)forwardingTargetForSelector:(SEL)aSelector { if ([SomeObj respondsToSelector:aSelector]) { return someObj; } return nil; }
若是 SomeObj 可以響應 aSelector,咱們就將此消息轉發到 someObj. 調試
若是SomeObj 不能響應,函數返回了 nil code
此時 runtime system將調用 orm
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *signature = [super methodSignatureForSelector:aSelector]; if (signature == nil) { signature = [OtherObj instanceMethodSignatureForSelector:aSelector]; } return signature; }
若是父類沒有實現此SEL,就詢問 OtherObj 是否實現此 SEL get
若是實現就返回NSMethodSignature cmd
不然就返回 nil,此時 runtime system就會調用 it
- (void)doesNotRecognizeSelector:(SEL)aSelector { NSLog(@"%@ %@",NSStringFromClass(self.class),NSStringFromSelector(_cmd)); }表示沒有實現此函數,並拋出NSInvalidArgumentException 異常
能夠在此函數中作程序最後的處理 io
說回去,若是OtherObj實現了此函數,則 runtime system 會調用
- (void)forwardInvocation:(NSInvocation *)anInvocation { if ([OtherObj instancesRespondToSelector:[anInvocation selector]]) [anInvocation invokeWithTarget:otherObj]; else [super forwardInvocation:anInvocation]; }這樣寫是爲了讓父類的轉發不被覆蓋,這裏若是不調用
[anInvocation invokeWithTarget:otherObj];
將不會真正調用函數
到此,轉發的方式與過程敘述完畢