消息转发流程

iOS开发过程中我们经常会碰到这样的报错:
unrecognized selector sent to instance **,我们调用了一个不存在的方法。
用OC消息机制来说就是:消息的接收者不过到对应的selector,这样就启动了消息转发机制。

抛出异常之前消息转发过程中的步骤:

1.(动态方法解析)询问是否有动态添加方法来进行处理
 +(BOOL)resolveInstanceMethod:(SEL)sel
void speak(id self, SEL _cmd,NSSting *msg){
    NSLog(@"Now I can speak.%@",msg);
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    
    NSLog(@"resolveInstanceMethod:  %@", NSStringFromSelector(sel));
    if (sel == @selector(speak)) {
       
      #动态添加方法
       return   class_addMethod([self class], sel, (IMP)speak, "V@:@");
   
    }
    return [super resolveInstanceMethod:sel];
}

class_addMethod方法动态添加了一个speak的实现方法来解决掉这条未知的消息,
此时消息转发过程提前结束。

2.(快速转发)询问是否有别的类实现该方法
- (id)forwardingTargetForSelector:(SEL)aSelector
- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"forwardingTargetForSelector:  %@", NSStringFromSelector(aSelector));
    Bird *bird = [[Bird alloc] init];
    if ([bird respondsToSelector: aSelector]) {
        return bird;
    }
    return [super forwardingTargetForSelector: aSelector];
}
// Bird.m
- (void)fly {
    NSLog(@"I am a bird, I can fly.");
}

其它类能实现相应方法,则返回相应实例响应对应方法,消息转发提前结束。

3. 调用签名方法并转发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
- (void)forwardInvocation:(NSInvocation *)anInvocation

调用forwardInvocation方法前先调用方法签名

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSLog(@"method signature for selector: %@", NSStringFromSelector(aSelector));
    if (aSelector == @selector(code)) {
        return [NSMethodSignature signatureWithObjCTypes:"V@:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"forwardInvocation: %@", NSStringFromSelector([anInvocation selector]));
    if ([anInvocation selector] == @selector(code)) {
       
        Monkey *monkey = [[Monkey alloc] init];
        [anInvocation invokeWithTarget:monkey];
  
  } else{

       [supre  forwardInvocation:anInvocation];
    }  
}

signatureWithObjCTypes
第一个表示返回值类型,例如:@为id类型,v为void类型
第二个表示函数调用者类型self,即为id类型。一般表示为@
第三个表示SEL方法选择器,一般表示为:冒号。
第四个表示参数类型。例如:i表示int类型

#获取类型编码字符串
NSLog(@"id 类型的编码是:%s",@encode(id));      //@
4. 最后都不能处理,进入Crash
- (void)doesNotRecognizeSelector:(SEL)aSelector{
      NSLog(@"找不到方法");
}

你可能感兴趣的:(消息转发流程)