前面我们已经讲解Runtime的基本概念和基本使用,如果大家对Runtime机制不是很了解,可以先看一下以前的博客,会对理解这篇博客有所帮助!!!

Runtime基本概念:https://www.cnblogs.com/guohai-stronger/p/9154889.html

Runtime基本使用:https://www.cnblogs.com/guohai-stronger/p/9184356.html

看过上面两篇博客之后,大家可能会对Runtime有所了解,但在上述讲述Runtime还有一个问题,当对象无法接收到相关的消息时候,又会发生什么?这就是我们即将讲的消息转发机制

一、前言

在讲述消息转发机制前,先通过一个简单的例子

id num = @;
//输出123
NSLog(@"%@", num);
//程序崩溃,报错[__NSCFNumber appendString:]: unrecognized selector sent to instance 0x7b27
[num appendString:@"Hello World"];

在程序代码中加入上面代码,运行过程为:先在相关的类中,搜索方法列表,如果出现找不到则会一直向上搜索到根部(也就是NSObject);如果出现还找不到并且消息转发都失败,此时就会执行doesNotRecognizeSelector:紧接着方法报unrecognized selector错误?

下面我们来讲述消息转发的过程中,为什么经常出现消息的最后三次机会?

第一步:所属类的动态方法解析

首先,如果沿着继承树没有搜索到相关的方法时,则就会向接受者所属的类进行一次请求,看是否可以动态的添加一个方法,如下:

+(BOOL)resolveInstanceMethod:(SEL)name

注意这是一个类方法,因为向接受者所属的类进行一次请求。

下面我们举个例子:

#import "ViewController.h"
#import <objc/runtime.h> @interface ViewController () @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Runtime";
[self performSelector:@selector(dynamicSelector) withObject:nil];
} + (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(dynamicSelector)) {
class_addMethod([self class],sel, (IMP)myMehtod,"v@:");
return YES;
}else{
return [super resolveInstanceMethod:sel];
} } void myMehtod(id self,SEL _cmd){
NSLog(@"This is added dynamic");
}

在看结果之前,我们先简单了解下:class_addMethod(上面出现的)

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

此函数共有四个参数:

  • Class cls:要添加的类对象
  • name:添加后的selector方法名字
  • imp:实现方法
  • type:方法参数的编码

方法的返回值为BOOL类型:YES表示本类可以处理;NO代表需要使用转发机制。

下面是上面的运行结果,结果如下:

如果第一步不能处理,会进行到第二步。

第二步:调用forwardingTargetForSelector把任务转发给另一个对象。

#import "ViewController.h"
#import <objc/runtime.h> @interface CustomObject : NSObject
-(void)dynamicSelector;
@end
@implementation CustomObject -(void)dynamicSelector{
NSLog(@"hello world");
}
@end @interface ViewController ()
@property (strong,nonatomic)CustomObject * myObj;
@end
@implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
self.myObj = [[CustomObject alloc] init];
[self performSelector:@selector(dynamicSelector) withObject:nil]; } -(id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(dynamicSelector) && [self.myObj respondsToSelector:@selector(dynamicSelector)]) {
return self.myObj;
}else{
return [super forwardingTargetForSelector:aSelector];
} }
@end

如果第二步骤也不能处理的时候,会交给第三步骤。

第三步:调用forwardInvocation转发给其他

#import "ViewController.h"
#import <objc/runtime.h> @interface CustomObject : NSObject
-(void)dynamicSelector;
@end
@implementation CustomObject -(void)dynamicSelector{
NSLog(@"hello world");
}
@end
@interface ViewController ()
@property (strong,nonatomic)CustomObject * myObj;
@end
@implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
self.myObj = [[CustomObject alloc] init];
[self performSelector:@selector(dynamicSelector) withObject:nil]; }
-(void)forwardInvocation:(NSInvocation *)anInvocation{
if ([self.myObj respondsToSelector:[anInvocation selector]]) {
[anInvocation invokeWithTarget:self.myObj];
}else{
[super forwardInvocation:anInvocation];
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
return [CustomObject instanceMethodSignatureForSelector:aSelector];
}
@end

上面就是iOS Runtime消息的转发机制,欢迎指正!!!

iOS Runtime的消息转发机制的更多相关文章

  1. OC:浅析Runtime中消息转发机制

    一.介绍 OC是一门动态性语言,其实现的本质是利用runtime机制.在runtime中,对象调用方法,其实就是给对象发送一个消息,也即objc_msgSend().在这个消息发送的过程中,系统会进行 ...

  2. iOS的消息转发机制详解

    iOS开发过程中,有一类的错误会经常遇到,就是找不到所调用的方法,当然这类问题比较好解决,给当前对象或其父类对象添加该方法即可,使得编译器在编译时能正确找到该方法:或者,还有另外的方法,由于Objec ...

  3. iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制

    你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...

  4. iOS 消息转发机制

    这篇博客的前置知识点是 OC 的消息传递机制,如果你对此还不了解,请先学习之,再来看这篇.这篇博客我尝试用口语的方式像讲述 PPT 一样给大家讲述这个知识点. 我们来思考一个问题,如果对象在收到无法解 ...

  5. iOS消息转发机制

    iOS消息转发机制 “消息派发系统”(message-dispatch system) 若想令类能够理解某条消息,我们必须实现出对应的方法才行.但是,在编译器向类发送其无法解读的消息时并不会报错,因为 ...

  6. 理解Objective-C Runtime(三)消息转发机制

    消息转发机制概述 上一篇博客消息传递机制中讲解了Objective-C中对象的「消息传递机制」.本文需要讲解另外一个重要问题:当对象受到无法处理的消息之后会发生什么情况? 显然,若想令类能理解某条消息 ...

  7. runtime之消息转发

    前言 在上一篇文章中我们初尝了runtime的黑魔法,可以在程序编译阶段就获取到成员变量的名字,特性以及动态的给对象增加属性等等,在接下来中我们进一步了解OC的消息发送机制.如果之前没接触过runti ...

  8. Effective Objective-C 2.0 — 第12条:理解消息转发机制

    11 条讲解了对象的消息传递机制 12条讲解对象在收到无法解读的消息之后会发生什么,就会启动“消息转发”(message forwarding)机制, 若对象无法响应某个选择子,则进入消息转发流程. ...

  9. runtime消息转发机制

    Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制.而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库.它是 Objective- ...

随机推荐

  1. Java VisualVM使用:堆OOM

    背景 近期遇到了一个java.lang.OutOfMemoryError: Java heap space的问题,排除了堆设置过小的问题,代码走查没有头绪,所以使用VisualVM工具分析堆内存情况. ...

  2. Android MVP理解

    Android默认采用的是MVC: View:对应于布局文件 Model:业务逻辑和实体模型 Controllor:对应于Activity 但是却存在很多问题: 1.这个View对应于布局文件,其实能 ...

  3. python面向对象编程对象和实例的理解

    给你一个眼神,自己体会

  4. Select的option事件问题

    一开始看你们会觉得没问题,我也就是觉得没问题所以才找不到错误所在. 问题出在option本身是没有事件的说法的,只能在select里添加事件,再获取option的属性值 这是我的写法 select设置 ...

  5. java实现生产者/消费者的三种方式

    package com.wenki.thread; import java.util.LinkedList; import java.util.concurrent.LinkedBlockingQue ...

  6. MySQL MEB常见用法

    1. 备份成镜像 备份: ./mysqlbackup --socket=/usr/local/mysql-advanced--linux-glibc2.-x86_64/data/mysql.sock ...

  7. spark报错:warn util.utils::service &#39;sparkUI&#39; can not bind on part 4040.Attempting port 4041.

    转载自:https://blog.csdn.net/weixin_41629917/article/details/83190258

  8. python3之os、sys

    os模块 # 显示当前使用平台:"nt":windows;"posix":Linux >>> os.name 'nt' # 当前工作目录 &g ...

  9. Redis 总结

    Redis官网下载地址: https://redis.io/ Redis 客户端可视化:https://redisdesktop.com/download 一.Redis 是什么? 1.key-val ...

  10. 设置Linux系统的空闲等待时间TMOUT

    为了增强Linux系统的安全性,我们需要在用户输入空闲一段时间后自动断开,这个操作可以由设置TMOUT值来实现.将以下字段加入到/etc/profile 中即可(对所有用户生效). export TM ...