iOS的消息轉發機制

OC由於運行時特性,可以在運行期間動態添加方法,這個尋找動態添加的方法的過程就是動態消息轉發。
iOS的消息轉發機制分爲三個步驟:動態方法解析、快速消息轉發機制、標準消息轉發機制
在這裏插入圖片描述

(一)動態方法解析
首先是徵詢接收者所屬的類,看其是否能動態添加調用的方法,來處理當前這個未知的選擇子;

-(BOOL)resolveInstanceMethod:(SEL)selector或者+(BOOL)resolveClassMethod:(SEL)selector;讓開發者有機會提供一個函數實現;若返回YES,說明已提供實現,那運行時系統就會重新啓動一次消息發送的過程若爲NO,則進入消息轉發階段-快速消息轉發

void dynamicMethodIMP(id self, SEL _cmd) {  
    NSLog(@" >> dynamicMethodIMP");  
}  
  
+ (BOOL)resolveInstanceMethod:(SEL)selector  
{     
    NSLog(@" >> Instance resolving %@", NSStringFromSelector(selector));  
      
    if (name == @selector(MissMethod)) {  
        class_addMethod([self class], selector, (IMP)dynamicMethodIMP, "v@:");  
        return YES;  
    }  
      
    return [super resolveInstanceMethod:name];  
}  

(二)快速消息轉發
尋找是否在其他對象內有該方法實現,並將該消息轉發給這個對象-(id)forwardingTargetForSelector:(SEL)selector ,如果目標對象實現了該方法,Runtime這時就會調用這個方法,給你把這個消息轉發給其他對象的機會.只要這個方法返回的不是nil和self,整個消息發送的過程就會被重啓,當然返回的對象會變成return的對象,否則就會繼續nurmal fowarding

- (id)forwardingTargetForSelector:(SEL)aSelector  
{  
    TargetObj *obj = [[TargetObj alloc]init];  
    if ([obj respondsToSelector:aSelector]) {  
        return doctor;  
    }  
    return nil;  
} 

(三)標準消息轉發(normal forwarding)
這一步是消息轉發的最後一步,首先會發送- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 消息獲得函數的參數和返回值,如果返回nil,runtime則會發出doesNotRecognizeSelector消息,然後crash,若是返回了一個函數簽名,runtime就會創建一個NSInvocation對象併發送- (void)forwardInvocation:(NSInvocation *)Invocation 消息給目標對象

+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [JaySwizzler swizzleSelector:@selector(methodSignatureForSelector:) onClass:[NSObject class] swizzleTargetSel:@selector(user_methodSignatureForSelector:) classType:NO];
        [JaySwizzler swizzleSelector:@selector(forwardInvocation:) onClass:[NSObject class] swizzleTargetSel:@selector(user_forwardInvocation:) classType:NO];
        
    });
 
}
- (NSMethodSignature *)user_methodSignatureForSelector:(SEL)aSelector{
    
    NSMethodSignature *ms = [self user_methodSignatureForSelector:aSelector];
    if (ms){
        return ms;
    }
    else{
        return [[self class] instanceMethodSignatureForSelector:@selector(noSelector)];
    }
}

- (void)noSelector{
    NSLog(@"完啦完啦沒有方法");
    
}
- (void)user_forwardInvocation:(NSInvocation *)anInvocation{
    
    @try {
        [self user_forwardInvocation:anInvocation];
        
    } @catch (NSException *exception) {
        //捕獲異常,根據exception打印出堆棧信息,同時也避免了程序崩潰
        NSLog(@"我要上報");
        NSLog(@"%@%@%@",exception.name,exception.reason,exception.userInfo);
        [JayStackLogManager outputStackLog];
        //上報
    } @finally {
        
    }
    
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章