runTime 的消息转发机制

/**

 *  首先,方法在调用时,系统会查看这个对象能否接收这个消息(查看这个类有没有这个方法,或者有没有实现这个方法。),如果不能并且只在不能的情况下,就会调用下面这几个方法,给你补救的机会,你可以先理解为几套防止程序crash的备选方案,我们就是利用这几个方案进行消息转发,注意一点,前一套方案实现后一套方法就不会执行。如果这几套方案你都没有做处理,那么程序就会报错crash

 

 方案一:

 

 + (BOOL)resolveInstanceMethod:(SEL)sel。// 处理实例方法

 + (BOOL)resolveClassMethod:(SEL)sel。  //处理类方法

 

 方案二:

 

 - (id)forwardingTargetForSelector:(SEL)aSelector

 

 方案三:

 

 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;

 - (void)forwardInvocation:(NSInvocation *)anInvocation;

 

 */

现在在一个类里面写下如下代码,但是这个类并没有 test4 这个方法的实现,然后就报错了

 [self performSelector:@selector(test4) withObject:nil];

[ViewController test4]: unrecognized selector sent to instance 0x7fbab94098a0'



现在我们来用方案一来解决

在当前类里面添加代码

void dynamicMethodIMP(id self, SEL _cmd) {

    NSLog(@" >> dynamicMethodIMP");

}


+(BOOL)resolveInstanceMethod:(SEL)sel {

    

    

    if (sel == @selector(test4)) {

        

        class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "v@:");

        return YES; 

    }

    return NO;   

}


打印结果:

2017-03-07 16:54:13.815 runTime[88709:10317153]  >> dynamicMethodIMP


第一个方案是为不存在的方法临时添加处理的方法。现在我们用第二种方案,删除方案一代码添加

- (id)forwardingTargetForSelector:(SEL)aSelector {

    

    return [FirstViewController new];

}


其中FirstViewController 里面有实现方法

- (void)test4 {

    NSLog(@"FirstViewController carryout test4");

}

然后打印结果就是

2017-03-07 16:56:38.385 runTime[89099:10319537] FirstViewController carryout test4


方案二 就是转移了实现方法的类 ,返回一个类来代替本类实现不了的方法


接下来是方案三

/**

 *  方案三

 开头我们要找的错误unrecognized selector sent to instance原因,原来就是因为methodSignatureForSelector这个方法中,由于没有找到run对应的实现方法,所以返回了一个空的方法签名,最终导致程序报错崩溃。

 

 所以我们需要做的是自己新建方法签名,再在forwardInvocation中用你要转发的那个对象调用这个对应的签名,这样也实现了消息转发。

 */


/**

 *  methodSignatureForSelector

 *  用来生成方法签名, 这个签名就是给forwardInvocation中参数NSInvocation调用的

 *

 */


- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {

    

    NSString *sel = NSStringFromSelector(aSelector);

    if ([sel isEqualToString:@"test4"]) {

        return [NSMethodSignature signatureWithObjCTypes:"v@:"];

    }

    return [super methodSignatureForSelector:aSelector];

}

-(void)forwardInvocation:(NSInvocation *)anInvocation

{

    SEL selector = [anInvocation selector];

    // 新建需要转发消息的对象

    FirstViewController *car = [[FirstViewController alloc] init];

    if ([car respondsToSelector:selector]) {

        // 唤醒这个方法

        [anInvocation invokeWithTarget:car];

    }

}


打印结果

2017-03-07 17:09:51.908 runTime[91235:10334599] FirstViewController carryout test4


这个效果和第二种结果一样


/**

 *  关于生成签名类型"v@:"解释一下, 每个方法会默认隐藏两个参数, self, _cmd

 self 代表方法调用者, _cmd 代表这个方法SEL, 签名类型就是用来描述这个方法的返回值, 参数的,

 v代表返回值为void, @表示self, :表示_cmd

 */





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值