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

iOS Runtime 消息转发机制

作者: liang1030 | 来源:发表于2021-12-01 10:30 被阅读0次

运行时阶段的消息发送的详细步骤如下:

1,检测selector是不是需要忽略的。比如 Mac OS X 开发,有了垃圾回收就不会理会retain、release 这些函数了。

2,检测target 是不是nil对象。ObjC 的特性是允许对一个 nil对象执行任何一个方法不会Crash,因为会被忽略掉。

3,如果上面两个都通过了,那就开始查找这个类的 IMP ,先从 cache 里面找,若可以找得到就跳到对应的函数去执行。

4,若果在cache里找不到就找一下方法列表methodLists。

5,如果methodLists找不到,就到超类的方法列表里查找,一直找,直到找打NSObject类为止。

6,如果还找不到,Runtime就提供了如下三种方法来处理:动态方法解析、消息接收者重定向、消息重定向,这三种方法调用关系如下图:

消息转发机制.jpeg

消息机制共分为3大步骤:
1.Method resolution 方法解析处理阶段

+(BOOL)resolveInstanceMethod:(SEL)sel;
+(BOOL)resolveClassMethod:(SEL)sel;

2.Fast forwarding 快速转发阶段

-(id)forwardingTargetForSelector:(SEL)aSelector;

3.Normal forwarding 常规转发阶段

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
-(void)forwardInvocation:(NSInvocation *)anInvocation;

那么如果想要不抛出unrecognized selector 的报错,也就需要从这3步里面来做补救。

第一步:Method resolution 方法解析处理阶段

如果调用了对象方法首先会进行+(BOOL)resolveInstanceMethod:(SEL)sel判断
如果调用了类方法 首先会进行 +(BOOL)resolveClassMethod:(SEL)sel判断

+(BOOL)resolveInstanceMethod:(SEL)sel {
    //判断是否为外部调用的方法
    if ([NSStringFromSelector(sel) isEqualToString:@"testFunction"]) {
        /**
         对类进行对象方法 需要把方法添加进入类内
         */
        [LMRuntimeTool addMethodWithClass:[self class] withMethodSel:sel withImpMethodSel:@selector(addDynamicMethod)];
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

两个方法都为类方法,如果YES则能接受消息 NO不能接受消息 进入第二步

第二步:Fast forwarding 快速转发阶段 (后面阶段都针对对象来处理,不考虑类方法)

-(id)forwardingTargetForSelector:(SEL)aSelector{
  if ([NSStringFromSelector(aSelector) isEqualToString:@"testFunction"]) {
        return [BackupTestMessage new];
    }
    return [super forwardingTargetForSelector:aSelector];
}

第三步:Normal forwarding 常规转发阶段

如果第2步返回self或者nil,则说明没有可以响应的目标 则进入第三步。
第三步的消息转发机制本质上跟第二步是一样的都是切换接受消息的对象,但是第三步切换响应目标更复杂一些,第二步里面只需返回一个可以响应的对象就可以了,第三步还需要手动将响应方法切换给备用响应对象。
第三步有2个步骤:

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    //如果返回为nil则进行手动创建签名
   if ([super methodSignatureForSelector:aSelector]==nil) {
        NSMethodSignature * sign = [NSMethodSignature signatureWithObjCTypes:"v@:"];
        return sign;
    }
    return [super methodSignatureForSelector:aSelector];
}
-(void)forwardInvocation:(NSInvocation *)anInvocation {
    //创建备用对象
    BackupTestMessage * backUp = [BackupTestMessage new];
    SEL sel = anInvocation.selector;
    //判断备用对象是否可以响应传递进来等待响应的SEL
    if ([backUp respondsToSelector:sel]) {
        [anInvocation invokeWithTarget:backUp];
    }else{
       // 如果备用对象不能响应 则抛出异常
        [self doesNotRecognizeSelector:sel];
    }
}

总结:

1,从以上的代码可以看出,forwardingTargetForSelector仅支持一个对象的返回,也就是说消息只能被转发给一个对象,而forwardInvocation可以将消息同事转发给任意多个对象,这就是两者的最大区别。

2,虽然理论上可以重载doesNotRecognizeSelector函数实现保证不抛出异常(不调用super实现),但是苹果文档着重提出"一定不能让这个函数就这么结束掉,必须抛出异常"。

3,forwardInvocation甚至能够修改消息的内容,用于实现更强大的功能。

参考链接:
https://www.jianshu.com/p/fdd8f5225f0c
https://www.jianshu.com/p/d4b55dae9a0d

相关文章

  • runtime系列文章总结

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

  • 消息转发机制原理?

    iOS runtime探究(二): 从runtime开始深入理解OC消息转发机制https://www.jians...

  • Runtime 的应用

    前面我们说到:Runtime 消息传递机制Runtime 消息转发机制Runtime 交换方法今天我们来谈谈Run...

  • iOS 消息转发机制 Runtime

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

  • iOS Runtime 消息转发机制

    运行时阶段的消息发送的详细步骤如下: 1,检测selector是不是需要忽略的。比如 Mac OS X 开发,有了...

  • Effective Objective-C读后笔记(2)

    11、runtime消息转发机制 runtime的消息转发流程图消息转发 消息转发的示例实现 这里也给大家推荐一篇...

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

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

  • iOS消息转发机制

    消息转发机制: 消息转发机制是相对于消息传递机制而言的。 1、消息(传递)机制 RunTime简称运行时。就是系统...

  • iOS runtime 消息机制及消息转发

    Sending Messages 在 Objective-C 中,如果向某对象传递消息,那就会使用动态绑定机制来决...

  • iOS runtime消息转发机制等

    消息转发机制分可以为三步,第一步:动态方法解析,询问该类是否能动态添加该方法,执行方法为resolveInstan...

网友评论

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

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