美文网首页iOS学习专题底层开发-基础知识
runtime 消息转发机制(最详细流程)

runtime 消息转发机制(最详细流程)

作者: 书上说says | 来源:发表于2019-05-05 12:12 被阅读29次

说到runtime,就不得不讲到最重要的消息转发机制,转发的流程图如下:


173709-7bcc4302c515f1e0.png

在OC里面,所有的方法调用,在运行时的时候都可以看作是objc_msgSend(obj,@selector())的调用

1.正常的方法调用

person.h文件,声明方法

#import <Foundation/Foundation.h>

@interface Person : NSObject
-(void)sendMessage:(NSString *)msg;
@end

person.m文件

#import "Person.h"
#import "Child.h"
#import <objc/runtime.h>
@implementation Person
- (void)sendMessage:(NSString *)msg{
    NSLog(@"person send msg:%@",msg);
}
@end

如果person.m实现了-(void)sendMessage:(NSString *)msg 方法,那么将会调用该方法,结果如图:


image.png

如果没有实现这个方法,则会报错没有该方法


image.png

那么实现消息转发机制的方法,就可以解决这个问题:

  1. 如果没有实现改方法,会先进行动态解析,调用+ (BOOL)resolveInstanceMethod:(SEL)sel方法
#import "Person.h"
#import "Child.h"
#import <objc/runtime.h>
@implementation Person

//- (void)sendMessage:(NSString *)msg{
//    NSLog(@"person send msg:%@",msg);
//}


void sendMessage(id self,SEL _cmd,NSString *msg) {
    NSLog(@"send msg:%@",msg);
}

//动态解析
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    NSLog(@"动态方法解析");
    NSString *methodName = NSStringFromSelector(sel);
    if ([methodName isEqualToString:@"sendMessage:"]) {
        return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");
    }
    return NO;
}
@end

image.png

2.如果第一步的动态解析也没有找到方法,那么将会进行快速转发,调用- (id)forwardingTargetForSelector:(SEL)aSelector可以在本类方法列表未找到方法的时候,转发给其他类,并返回该类对象:

Child.m 文件实现了一个方法

#import "Child.h"

@implementation Child
- (void)sendMessage:(NSString *)msg{
    NSLog(@"child send msg:%@",msg);
}
@end
#import "Person.h"
#import "Child.h"
#import <objc/runtime.h>
@implementation Person

//- (void)sendMessage:(NSString *)msg{
//    NSLog(@"person send msg:%@",msg);
//}


//void sendMessage(id self,SEL _cmd,NSString *msg) {
//    NSLog(@"send msg:%@",msg);
//}

//动态解析
+ (BOOL)resolveInstanceMethod:(SEL)sel{
//    NSLog(@"动态方法解析");
//    NSString *methodName = NSStringFromSelector(sel);
//    if ([methodName isEqualToString:@"sendMessage:"]) {
//        return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");
//    }
    return NO;
}

//快速转发
- (id)forwardingTargetForSelector:(SEL)aSelector{
    NSString *methodName = NSStringFromSelector(aSelector);
    if ([methodName isEqualToString:@"sendMessage:"]) {
        return [Child new];
    }
    return [super forwardingTargetForSelector:aSelector];
}
@end

运行结果:


image.png

3.如果没有快速转发也失败了,那么将会返回nil,进行慢速转发,慢速转发需要实现两个方法:
(1)- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
(2) - (void)forwardInvocation:(NSInvocation *)anInvocation

#import "Person.h"
#import "Child.h"
#import <objc/runtime.h>
@implementation Person

//- (void)sendMessage:(NSString *)msg{
//    NSLog(@"person send msg:%@",msg);
//}


//void sendMessage(id self,SEL _cmd,NSString *msg) {
//    NSLog(@"send msg:%@",msg);
//}

//动态解析
+ (BOOL)resolveInstanceMethod:(SEL)sel{
//    NSLog(@"动态方法解析");
//    NSString *methodName = NSStringFromSelector(sel);
//    if ([methodName isEqualToString:@"sendMessage:"]) {
//        return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");
//    }
    return NO;
}

//快速转发
- (id)forwardingTargetForSelector:(SEL)aSelector{
//    NSString *methodName = NSStringFromSelector(aSelector);
//    if ([methodName isEqualToString:@"sendMessage:"]) {
//        return [Child new];
//    }
    return [super forwardingTargetForSelector:aSelector];

}

//慢速转发 1.签名 2.转发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    NSString *methodName = NSStringFromSelector(aSelector);
    if ([methodName isEqualToString:@"sendMessage:"]) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation{
    SEL sel = anInvocation.selector;
    Child *child = [Child new];
    if ([child respondsToSelector:sel]) {
        [anInvocation invokeWithTarget:child];
    }else {
        [super forwardInvocation:anInvocation];
    }

}

结果如下,还是转发给了child的类对象,消息转发成功:


image.png

4.最后,如果消息转发失败,那么将会报错,但是为了程序防止崩溃,还是有方法可以处理的,因为到最后如果还没有转发成功,那么将会走-(void)doesNotRecognizeSelector:(SEL)aSelector方法:

#import "Person.h"
#import "Child.h"
#import <objc/runtime.h>
@implementation Person

//- (void)sendMessage:(NSString *)msg{
//    NSLog(@"person send msg:%@",msg);
//}


//void sendMessage(id self,SEL _cmd,NSString *msg) {
//    NSLog(@"send msg:%@",msg);
//}

//动态解析
+ (BOOL)resolveInstanceMethod:(SEL)sel{
//    NSLog(@"动态方法解析");
//    NSString *methodName = NSStringFromSelector(sel);
//    if ([methodName isEqualToString:@"sendMessage:"]) {
//        return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");
//    }
    return NO;
}

//快速转发
- (id)forwardingTargetForSelector:(SEL)aSelector{
//    NSString *methodName = NSStringFromSelector(aSelector);
//    if ([methodName isEqualToString:@"sendMessage:"]) {
//        return [Child new];
//    }
    return [super forwardingTargetForSelector:aSelector];

}

//慢速转发 1.签名 2.转发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    NSString *methodName = NSStringFromSelector(aSelector);
    if ([methodName isEqualToString:@"sendMessage:"]) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation{
//    SEL sel = anInvocation.selector;
//    Child *child = [Child new];
//    if ([child respondsToSelector:sel]) {
//        [anInvocation invokeWithTarget:child];
//    }else {
//        [super forwardInvocation:anInvocation];
//    }
    
    [super forwardInvocation:anInvocation];

}
-(void)doesNotRecognizeSelector:(SEL)aSelector{
    NSLog(@"无法识别该消息:%@",NSStringFromSelector(aSelector));
}

@end

运行结果:


image.png

到此一个完整的消息转发机制例子就演示完毕了,如果有需要的可以下载完整的源码,本文也是参考了部分大神的文章,对自己的一个小结,如果有误导的地方,欢迎大家指正以及补充***

相关文章

  • runtime 消息转发机制(最详细流程)

    说到runtime,就不得不讲到最重要的消息转发机制,转发的流程图如下: 在OC里面,所有的方法调用,在运行时的时...

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

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

  • Runtime知识点整理1

    OC消息机制?消息转发机制流程?什么是Runtime?什么场景下使用? ==============巴拉巴拉......

  • 读李峰峰博客笔记之消息转发

    消息转发 消息转发的流程如下图: 重定向 消息转发机制执行前,Runtime 系统允许我们替换消息的接收者为其他对...

  • runtime系列文章总结

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

  • Runtime 的应用

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

  • Runtime主要用处

    深入理解Objective-C Runtime机制 一:消息转发流程和机制 1、实例方法:本类的缓存方法列表->本...

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

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

  • iOS消息转发机制

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

  • iOS底层第11-->16天 -- Runtime

    引导语: OC消息机制是什么? 消息转发流程是什么? 什么是Runtime,项目中如何使用? 前言引导:为了避免读...

网友评论

    本文标题:runtime 消息转发机制(最详细流程)

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