美文网首页
Runtime消息分发(三)

Runtime消息分发(三)

作者: wemt | 来源:发表于2018-05-06 10:34 被阅读0次

上一节在描述Method数据结构时,区分了SEL和IMP。知道了在OC中是通过发送消息来执行代码的。
消息发送的流程也只有两步:

  1. 通过SEL查找IMP。
  2. 执行IMP。

那么SEL是怎样去查找IMP的呢?如果找不到会怎么办?
1.1 首先会在本类找,如果找不到则会在其继承链上寻找。
1.2 在动态绑定的方法中寻找IMP。
1.3 消息转发。

由于前面两步都没有提供回调,所以只需要将注意力放在第三步消息转发上面。
消息转发又分成3个步骤:
1.3.1 动态方法解析
1.3.2 备援接收者
1.3.3 完整消息转发

一个完整SEL查找IMP的过程如图:


SEL寻找IMP过程.png

动态方法解析

在没有找到IMP时,首先会调用下面的方法:

//类方法
+ (BOOL)resolveClassMethod:(SEL)sel
//实例方法
+ (BOOL)resolveInstanceMethod:(SEL)sel

在这个方法中,只需要给对象动态添加一个方法并且返回YES,表明可以处理。

//自定义的C函数。
void messageBirthDate(){
    NSLog(@"CType :MessageForward birthDate");
}
//@param sel  方法的选择子
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    if ([@"messageBirthDate" isEqualToString:NSStringFromSelector(selector)]){
        //添加方法
        //@param class 对象的类
        //@param sel 选择子
        //@param IMP IMP
        //@param types 参数和返回类型编码
        class_addMethod([self class], selector, (IMP)messageBirthDate, "vv");
        return YES;
    }
    return [super resolveInstanceMethod:selector];
}

备援接受者

如果动态方法解析没有进行处理,则会调用下面的方法,看能否进行处理:

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    if (aSelector == @selector(birthDate))
    {
        return [SonClass new];
    }
    return [super forwardingTargetForSelector:aSelector];
}

这个方法实际上是将消息转发到有对应SEL的类去进行处理。

完整的消息转发

如果备援接受者依然没有进行处理,则会进行完整的消息转发。完整的消息转发其实也就只有2步:
1.获取方法签名
2.执行函数调用相关内容。

//////////////消息转发
//1.获取方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
    if (!signature) {
        FatherClass *father = [[FatherClass alloc] init];
        signature = [father methodSignatureForSelector:@selector(birthDate)];//将fatherBirthDate的Signature转成 → birthDate的Signature
    }
    return signature;
}
//2.执行函数调用相关
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
//自己新组成一个invokation。
//    NSMethodSignature *signature= [anInvocation methodSignature];//可以从前面anInvocation中去取。
    NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"@@:"];//也可以自己去生成。
    NSInvocation *newInvocation =[NSInvocation invocationWithMethodSignature:signature];
    FatherClass *father =[[FatherClass alloc] init]; 
    [newInvocation setTarget:father];
    [newInvocation setSelector:@selector(birthDate)];
    [newInvocation invoke];
    id retValue;
    [newInvocation getReturnValue:&retValue];
    NSLog(@"%@",(NSString *)retValue);
    [anInvocation setReturnValue:&retValue];
}

这里需要注意变量的作用域,在setTarget时,newInvocation不会去持有Target。所以需要自己控制变量的作用域。
在消息转发过程中,越靠后消息处理的成本也越大,但是能够进行的掌控也越多。至于需要在哪个部分进行截获处理,就需要按照具体需求来判断了。

异常处理

当完整详细转发还不能够处理时,则会走到异常处理了:

- (void)doesNotRecognizeSelector:(SEL)aSelector
{
    [super doesNotRecognizeSelector:aSelector];
}

在异常处理中,可以做一些异常上报的工作。

总结

1.介绍了SEL寻找IMP的过程。
2.介绍了消息转发的过程。


参考:

相关文章

  • Runtime消息分发(三)

    上一节在描述Method数据结构时,区分了SEL和IMP。知道了在OC中是通过发送消息来执行代码的。消息发送的流程...

  • Runtime 见闻整理

    Runtime 基本是用C和汇编写的Runtime 涉及三个点,面向对象,消息分发,消息转发 面向对象 Objec...

  • runtime底层实现原理

    一、Runtime介绍二、Runtime源码初探三、Runtime消息传递四、Runtime消息转发五、Runti...

  • Runtime初识(一)

    Runtime是什么 简单的说,Runtime的内容包括两个部分:1.消息分发。2.在运行时对代码进行动态的修改。...

  • 深入浅出Runtime

    Runtime运行时 目录 一、runtime 简介二、消息机制<了解>2.1 消息机制原理2.2 消息调用流程三...

  • ios-面试-OC 方法调用的过程原理

    OC中的所有方法调用,最终都是转换成runtime中的一个C语言消息分发函数: objc_msgSend(消息接收...

  • Runtime消息分发函数使用(四)

    在上一节消息分发中,使用到了NSMethodSignature和NSInvocation。这一节来看下这两者是干什...

  • runtime消息分发-OC方法调用原理

    概述你一定听说过“运行时是 Objective-C 的一个特色”,也经常在写方法调用。但你知道方法调用具体是个什么...

  • iOS - Runtime - 概念和方法交换

    runtime的概述runtime的相关概念runtime消息机制消息传递动态方法解析消息转发runtime的作用...

  • Runtime(三)消息转发

    Message Forwarding 向一个未处理响应消息的对象发送对应的消息,会发生错误。但是,runtime会...

网友评论

      本文标题:Runtime消息分发(三)

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