objc 消息轉發

今天忽然又興趣看了下 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];

將不會真正調用函數

到此,轉發的方式與過程敘述完畢

相關文章
相關標籤/搜索