美文网首页
iOS的消息转发机制

iOS的消息转发机制

作者: _烩面_ | 来源:发表于2018-01-22 00:29 被阅读87次

先上一bug:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[HomeViewController handleMessage]: unrecognized selector sent to instance 0x1635cf6e0'
这个bug是大家的老朋友了,就不介绍了!它是怎么产生的呢?
以HomeViewController为例,当HomeViewController不响应handleMessage消息时,则会去寻找它的父类,如果父类还没有,就会去找找寻它的父父类,直到NSObject。如果此时还未响应,消息分发机制就启动了,会依次调用下面的两个方法

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
- (void)doesNotRecognizeSelector:(SEL)aSelector

首先调用的methodSignatureForSelector:会返回一个空的方法签名,之后会走到doesNotRecognizeSelector:抛出一个致命异常,于是程序崩溃!

在刚才的分析中,由于系统最终未能成功响应handleMessage消息而崩溃。其实,在NSObject之后,系统抛出异常之前,我们是有机会去做一些处理的。这里一共有三次时机供我们选择,根据UIViewController的生命周期,我来依次介绍以下三种方法。

先来看一下流转图

方法流转图
方法一:动态添加方法
// 对应实例方法
+ (BOOL)resolveInstanceMethod:(SEL)sel 
// 对应类方法
+ (BOOL)resolveClassMethod:(SEL)sel 

以HomeViewController为例

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(handleMessage)) {
        class_addMethod([self class], sel, (IMP)surrogateHandleMessage, "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

void surrogateHandleMessage (id self, SEL _cmd) {
    NSLog(@"l am a surrogate method of handleMessage");
}

通过拦截并重写resolveInstanceMethod:方法,动态地添加方法surrogateHandleMessage,去实现handleMessage
相应的,若是类方法,则拦截并重写resolveClassMethod:

方法二 将消息转发给其它对象
- (id)forwardingTargetForSelector:(SEL)aSelector

可以这样实现

- (id)forwardingTargetForSelector:(SEL)aSelector {
    return [SurrogateViewController new];
}

这里初始化SurrogateViewController的一个实例,然后由这个实例去响应handleMessage消息。不过前提是SurrogateViewController有handleMessage方法并实现了它。

如果上面两种方法都没使用,那么你仍有机会,可以在消息分发的实现中去处理。

方法三 消息分发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
- (void)forwardInvocation:(NSInvocation *)anInvocation

先实现methodSignatureForSelector:方法,获取一个方法签名,然后在forwardInvocation:中进行消息的分发。

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(handleMessage)) {
        return [SurrogateViewController instanceMethodSignatureForSelector:@selector(newMethodOfHandleMessage)]
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    
    SEL selector = [anInvocation selector];
    if (selector == @selector(handleMessage)) {
        [anInvocation setSelector:@selector(newMethodOfHandleMessage)];
        SurrogateViewController *homeVC = [SurrogateViewController new];
        [anInvocation invokeWithTarget:homeVC];
    }
    else {
        [super forwardInvocation:anInvocation];
    }
}

以上三种方法可三选一。若实现了多个,则根据生命周期以先执行的为准,后执行的将被忽略。

参考
1https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105-SW1
2 https://www.jianshu.com/p/5127ce0628be
3 http://www.cocoachina.com/ios/20150604/12013.html

相关文章

  • runtime系列文章总结

    《iOS Runtime详解(消息机制,类元对象,缓存机制,消息转发)》《消息转发机制与Aspects源码解析》《...

  • iOS理解Objective-C中消息转发机制附Demo

    iOS理解Objective-C中消息转发机制附Demo iOS理解Objective-C中消息转发机制附Demo

  • iOS面试-基础

    [toc] Runloop AutoReleasePool 多线程 响应者链 消息响应机制 消息转发机制 iOS内...

  • iOS 消息转发机制

    今天大概学习了下iOS的消息转发机制,还是挺有收获,在此做下笔记,以便后面温习。 1.iOS的消息转发机制原理如下...

  • iOS面试题总结(二)

    iOS面试题(二) 消息发送和转发机制,SEL和IMP 消息发送转载自黄龙辉消息发送和消息转发机制 在Object...

  • Runtime

    相关简单介绍 消息机制消息传递机制消息转发机制-动态添加方法消息转发机制-快速转发消息转发机制-慢速转发消息转发机...

  • 深入了解runtime

    iOS经典讲解之[self class]和[super class]的区别 iOS的消息机制和消息转发 Objec...

  • iOS - 消息转发机制

    我们知道,OC是动态语言,所有的方法都会以消息的形式传递给对象,对象会根据方法的类型来进行实例方法或者类方法的选择...

  • 【iOS】消息转发机制

    1、动态方法解析 对象在收到无法处理的消息时,会调用下面的方法,前者是调用类方法时会调用,后者是调用对象方法时会调...

  • iOS消息转发机制

    OC消息转发 oc中的调用对象或者类不存在的方法,会执行一遍消息转发流程.消息转发主要包括4步 首先调用+ (BO...

网友评论

      本文标题:iOS的消息转发机制

      本文链接:https://www.haomeiwen.com/subject/xyyxaxtx.html