Runtime 消息传递

2017-04-28  本文已影响8人  Brucezhang1

*main.m

PersonA *personA = [[PersonA alloc]init];
[personA speechJapan];
- (void)speechJapan;

- (void)speechJapan{
    NSLog(@"speechJapan");
}
- (void)speechEnglish;
- (void)speechJapan;
- (void)speechEnglish{
    NSLog(@"speechEnglist");
}

// 此方法不是方法的实现,需要进行转化
- (void)speechNewLan{
     NSLog(@"speechNewLan");
}

// 将方法转换成方法的实现IMP
IMP convertToIMP(){
    return  class_getMethodImplementation([PersonA class], @selector(speechNewLan));
}
/* 当未找到speechJapan时,首先调用此方法,使有机会添加一个实现的方法
 如果添加了方法并且放回了Yes,则运行时系统会启用一次消息发送的过程。如果返回为NO,
 运行时系统则进入到下一步,消息转发(Message Forwarding)
 */

// 消息派发
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    if (sel == @selector(speechJapan)) {
        class_addMethod(self, sel, convertToIMP(), "");
        return YES;
    }
    return NO;
}


/*实现此方法,运行时系统就会调用次方法,将消息转发给其他指定的对象,
 比如转发给PersonB的对象
 
注:只要返回的对象不是nil或self,消息发送的整个过程就会启动
 发送的对象变为指定返回的对象,比如PersonB。如果返回的是nil或self,则进行下一步转发操作
 */
- (id)forwardingTargetForSelector:(SEL)aSelector{
    if (aSelector == @selector(speechJapan)) {
        PersonB *pB = [[PersonB alloc] init];
        return pB;
    }
    return [super forwardingTargetForSelector:aSelector];
}

// 消息转发第二步 Mormal forwrading

/* 获取方法签名
 调用此方法获取函数的参数和返会类型,如果此方法返回nil
 Runtime则会发出doseNotRecognizeSelector: 消息挂掉程序
 如果返回一个函数签名,Runtime则会创建一个NSINvocation对象,调用ForwradInvacation:
 发送消息给对象
 */
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    
    NSMethodSignature *sign = [[PersonB class] instanceMethodSignatureForSelector:aSelector];
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}

// 实现消息的转发
/*
 NSInvocation 实际上是对一个消息的描述,包括selector极其参数等信息
 所以可以在此方法中修改NSInvocation对象,然后调用invokeWithTarget:消息给对象
 */
- (void)forwardInvocation:(NSInvocation *)anInvocation{
    SEL sel = anInvocation.selector;
     PersonB *pB = [[PersonB alloc] init];
    if ([pB respondsToSelector:sel]) {
        [anInvocation invokeWithTarget:pB];
    }else{
        [self doesNotRecognizeSelector:sel];
    }
}

上一篇 下一篇

猜你喜欢

热点阅读