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

【iOS】消息转发机制

作者: zhangPeng丶 | 来源:发表于2018-04-02 15:12 被阅读67次

    简书http://www.jianshu.com/u/5690b3ad0a6f
    Bloghttp://blog.zhangpeng.site
    GitHubhttps://github.com/fullstack-zhangpeng

    消息转发

      当对象接收到无法解读的消息(unrecognized selector sent to instance 0x87),就会启动消息转发机制,由程序员指定处理方法。

    消息转发机制

    消息转发两大阶段

    1. 动态方法解析

      检查当前接收者能否动态添加方法,处理这个unrecognized selector

    2. 完整的消息转发

      第一阶段执行完毕后,如接收者不能以动态新增方法处理这个unrecognized selector,接下来,会分两种情况:

      • 有备援接收者(replacement receiver)

        在运行期将消息转给备援接收者,由备援接收者完成消息的处理。

      • 无备援接收者(replacement receiver)

        启动一套“完整的消息转发机制”,将消息封装到NSInvocation对象中,交给接收者处理。

    动态方法解析

    如果没有找到需要执行的方法,会根据方法的类型,执行不同的处理方法。

    处理无法调用的类方法

    + (BOOL)resolveClassMethod:(SEL)sel

    处理无法调用的实例方法

    + (BOOL)resolveInstanceMethod:(SEL)sel

    一般是提前写好相关的实现代码,通过Runtime在此处插入到类中。

    e.g.

    /**
     没有找到SEL的实现时会执行下方的方法
     @param sel 当前对象调用并且找不到IML的SEL
     @return 是否可以处理这个方法,并返回yes
     */
    + (BOOL)resolveInstanceMethod:(SEL)sel 
    {
    // 当返回YES时
    // 在这里通过Runtime在将已经写好实现的代码插入到类中。
    // ...
        return YES;
        
    // 当返回NO时
    // 会接着执行forwordingTargetForSelector:方法
    //    return NO;  
    }
    
    消息转发
    有备援接收者

      在方法- (id)forwardingTargetForSelector:(SEL)aSelector中返回可以处理该消息的对象,交由该对象去处理这个消息。

      如果此处返回nil,则表示没有其他对象可以处理这个消息,然后通过完整的消息转发机制来处理。

    /**
     将当前对象不存在的SEL传给其他存在该SEL的对象
     @param aSelector 当前类中不存在的SEL
     @return 存在该SEL的对象
     */
    - (id)forwardingTargetForSelector:(SEL)aSelector 
    {
    // 不传递给其他对象
    // 将会执行- (void)forwardInvocation:(NSInvocation *)anInvocation;
        return nil;
        
    // 传递给一个其他对象,处理这个方法。
    // 可以做相应的错误处理等
    // 让OtherClass中相应的SEL去执行该方法
    //    return [[OtherClass alloc] init];
    }
    
    无备援接收者

      如果接收者不能处理消息,并且没有备援接收者,最终只能采取一个完整的消息转发来处理消息。

      通过NSInvocation包装方法的目标、参数等,然后通过- (void)forwardInvocation:(NSInvocation *)invocation将消息指派给目标对象。

    - (void)forwardInvocation:(NSInvocation *)invocation
    {
        SecondClass * forwardClass = [SecondClass new];
        SEL sel = invocation.selector;
        if ([forwardClass respondsToSelector:sel]) {
            [invocation invokeWithTarget:forwardClass];
        } else {
            [self doesNotRecognizeSelector:sel];
        }
    }
    

    已上具体实现可以在RuntimeDemo的TestClass中找到。

    相关文章

      网友评论

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

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