iOS架构师_消息转发机制

2023-11-13

1.动态方法解析

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

//未实现类方法调用
+ (BOOL)resolveClassMethod:(SEL)sel
//未实现实例方法调用
+ (BOOL)resolveInstanceMethod:(SEL)sel

在该方法中,需要给对象所属类动态的添加一个方法,并返回YES,表明可以处理

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    NSString *method = NSStringFromSelector(sel);
    if ([@"playPiano" isEqualToString:method]) {
        /**
         添加方法

         @param self 调用该方法的对象
         @param sel 选择子
         @param IMP 新添加的方法,是c语言实现的
         @param 新添加的方法的类型,包含函数的返回值以及参数内容类型,eg:void xxx(NSString *name, int size),类型为:v@i
         */
        class_addMethod(self, sel, (IMP)playPiano, "v");
        return YES;
    }
    return NO;
}

使用这种办法的前提是:相关方法代码已经实现,只是在运行时将改方法动态添加到目标类中。例如CoreData中使用的@dynamic属性,就是在运行时动态添加方法实现。

2.备援接收者

经历了第一步后,如果该消息还是无法处理,那么就会调用下面的方法,查询是否有其它对象能够处理该消息。

- (id)forwardingTargetForSelector:(SEL)aSelector

在这个方法里,我们需要返回一个能够处理该消息的对象

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    NSString *seletorString = NSStringFromSelector(aSelector);
    if ([@"playPiano" isEqualToString:seletorString]) {
        Student *s = [[Student alloc] init];
        return s;
    }
    // 继续转发
    return [super forwardingTargetForSelector:aSelector];
}

3.完整的消息转发

经历了前两步,还是无法处理消息,那么就会做最后的尝试,先调用methodSignatureForSelector:获取方法签名,然后再调用forwardInvocation:进行处理,这一步的处理可以直接转发给其它对象,即和第二步的效果等效,但是很少有人这么干,因为消息处理越靠后,就表示处理消息的成本越大,性能的开销就越大。所以,在这种方式下,会改变消息内容,比如增加参数,改变选择子等等。

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

下面是改变选择子的例子,比如我们直接调用的是playPiano方法,最后转发给了traval:方法。

// 完整的消息转发
- (void)travel:(NSString*)city
{
    NSLog(@"Teacher travel:%@", city);
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSString *method = NSStringFromSelector(aSelector);
    if ([@"playPiano" isEqualToString:method]) {

        NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"];
        return signature;
    }
    return nil;
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    SEL sel = @selector(travel:);
    NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    anInvocation = [NSInvocation invocationWithMethodSignature:signature];
    [anInvocation setTarget:self];
    [anInvocation setSelector:@selector(travel:)];
    NSString *city = @"北京";
    // 消息的第一个参数是self,第二个参数是选择子,所以"北京"是第三个参数
    [anInvocation setArgument:&city atIndex:2];

    if ([self respondsToSelector:sel]) {
        [anInvocation invokeWithTarget:self];
        return;
    } else {
        Student *s = [[Student alloc] init];
        if ([s respondsToSelector:sel]) {
            [anInvocation invokeWithTarget:s];
            return;
        }
    }

    // 从继承树中查找
    [super forwardInvocation:anInvocation];
}

这里写图片描述

这里写图片描述

这里写图片描述

+ (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);//类方法
 + (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);//对象方法

 - (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);//快速消息转发

 //标准消息的转发
 - (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");
 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");

消息转发机制代码示例:

新建Person类进行演示

Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject
- (void)run;
@end

这里写图片描述

Person.m

#import "Person.h"
#import <objc/message.h>

@implementation Person

// 1.动态方法
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSLog(@"sel = %@", NSStringFromSelector(sel));

    // 1.判断没实现方法, 就动态添加方法
//    if (sel == @selector(run:)) {
//        // 动态添加方法
//        class_addMethod(self, sel, (IMP)newRun, "v@:@");
//        return YES;
//    }

    //2.动态添加的方法没有使用,就给super
    return [super resolveInstanceMethod:sel];
}

void newRun(id self,SEL sel, NSString *str) {
    NSLog(@"---run起来了没有 %@--",str);
}

// 二.消息转发重定向
- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"%@",NSStringFromSelector(aSelector));
    return [super forwardingTargetForSelector:aSelector];
//    return [[Animation alloc] init];
}


// 三.生成方法签名.
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    // 1. 转化字符串
    NSString *sel = NSStringFromSelector(aSelector);

    // 2.进行判断 手动生成签名
    if ([sel isEqualToString:@"run"]) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    } else {
    return [super methodSignatureForSelector:aSelector];
    }
}

// 四.拿到方法签名配发消息
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"-----%@",anInvocation);
    // 1.拿到这个消息
    SEL selector = [anInvocation selector];
    // 2.转发消息.
    Animation *anm = [[Animation alloc] init];

    if ([anm respondsToSelector:selector]) {
        // 调用这个对象,进行转发
        [anInvocation invokeWithTarget:anm];

    } else {
        [super forwardInvocation:anInvocation];
    }
}


// 五.抛出异常
- (void)doesNotRecognizeSelector:(SEL)aSelector {
    NSString *selStr = NSStringFromSelector(aSelector);
    NSLog(@"这个-----%@---方法不存在", selStr);
}

@end
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS架构师_消息转发机制 的相关文章

  • iOS进阶_密码学进阶(一.对称加密算法简介)

    加密算法 HASH 散列函数 不可逆 密码 识别 文件 识别 以下两种加密算法 都是可逆的 明文 gt 加密 gt 密文 密文 gt 解密 gt 明文 对称加密 传统加密算法 加密和解密使用同一个 密钥 密钥的保密工作就非常的重要 密钥会定
  • iOS进阶_密码学(四.抽取登录网络请求的单例)

    登录业务逻辑完善 在网络开发中 一般会有一个单例负责所有的网络请求 将这个网络登录的部分代码抽取出来 新建一个 类 复制方法 调整参数 测试登录能否成功运行 WTNetworkTools h import
  • iOS架构师_UML建模语言

    UML UML统称建模语言 面向对象软件的表转化建模语言 包含Booch MOT OOSE 工具 StarUML 时序图
  • iOS进阶_WebDav(五.WebDav的上传进度&多线程下载思路)

    WebDav的上传进度 import ViewController h interface ViewController
  • iOS架构-组件化(项目实战-项目首页架构)

    UI架构设计 设计模式 外观模式 代理模式 适配器模式 adapter 注意 一版本只是搭建结构 一 1 0 Tab搭建 二 1 1 新增UICollectionView 主页 gt 整体设计基于 gt UICollectionView 滑
  • iOS核心动画CoreAnimation系统进阶(赛贝尔曲线-菜单侧滑动画拆分动画详解)

    我们知道动画是基于绘制的 多次绘制贝塞尔的过程就会形成动画 流畅的动画效果会给用户带来不一样的使用体验 下面我们就让App开发中经常使用到的侧滑动画进行拆分详解 效果图如下 为侧滑动画封装一个slideMenuView 绘制侧滑动画需要下面
  • iOS进阶_多线程(二.线程间的状态)

    ViewController m 004 NSThread状态 Created by mac on 2018 4 27 Copyright 2018年 mac All rights reserved import ViewControlle
  • iOS架构-组件化(Carthage管理工具)

    一 Carthage项目管理工具使用 Step 1 安装 更新Homebrew工具 1 usr bin ruby e curl fsSL https raw githubusercontent com Homebrew install ma
  • iOS自动化布局-AutoLayout约束优先级

    约束的优先级 AutoLayout添加的约束中也有优先级 Priority 优先级的数值1 1000 分为两种情况 一种情况是我们经常添加的各种约束 默认值1000 最大值 优先执行 条件允许的话系统会自动满足我们的约束需求 第二种就是固有
  • Objective-C实现链式编程语法(DSL)

    您越着急开始写代码 代码就会花费越长的时间 Carlson University of Wisconsin 前言 熟悉Objective C这一门编程语言的人都知道 Objective C中方法的调用都是通过中括号 实现的 比如 self
  • iOS进阶_密码学(二.钥匙串访问)

    网络开发中的原则 在网络上不允许传输用户的明文隐私数据 在本地不允许保存用户的明文隐私数据 类似于QQ 微信的记住密码 在客户端本地保存用户加密后的密码 NSUserDefaults 明文保存才能反算 能够反算的算法 钥匙串访问 开放给开发
  • iOS进阶_NSURLConnection(被弃用的原因:Connection的缺点)

    NSURLConnection下载 我们在前面的文章中介绍了MAC电脑搭建Apache服务器 在Sites文件夹中放置一个视频文件MVVM mp4 pbb 通过NSURLConnection进行下载 访问http localhost 我们可
  • iOS架构师_消息转发机制

    1 动态方法解析 对象在收到无法处理的消息时 会调用下面的方法 前者是调用类方法时会调用 后者是调用对象方法时会调用 未实现类方法调用 BOOL resolveClassMethod SEL sel 未实现实例方法调用 BOOL resol
  • iOS开发之ReactiveCocoa框架(RAC)第五篇队列与高级函数

    h文件 import ViewController h import ReactiveCocoa interface ViewController end implementation ViewController void viewDid
  • iOS开发之Runtime运行时机制

    摘要 Objective C是基于C加入了面向对象特性和消息转发机制的动态语言 除编译器之外 还需用Runtime系统来动态创建类和对象 进行消息发送和转发 作者通过分析Apple开源的Runtime代码来深入理解OC的Runtime机制
  • iOS进阶_Log分类打印日志自动转换中文

    description方法是NSObject类的一个实例方法 因此所有的Object C对象都有description方法 description方法返回的永远是字符串 对于一个Person类 如果没有重写description方法 NSL
  • iOS开发 多线程的高级应用-信号量semaphore

    在iOS开发的道路上 多线程的重要性不言而喻 大部分我们都停留在基础的使用上面 缺乏高级应用 缺乏提升 是因为我们面对他太少 复杂的事情重复做 复杂的事务基础化 差距就是这样拉开了 言归正传 今天讲讲GCD的高级应用之信号量篇 一 信号量的
  • iOS进阶_NSURLSession(二.断点续传)

    断点续传 从上一篇文章中 我们了解了使用NSURLSession进行文件下载 我们在其基础上继续探索NSURLSession的断点续传 在NSURLSession中 我们使用reumeData来存储下载的数据进度 import ViewCo
  • iOS进阶_kvc使用注意事项

    细节1 我们在项目中使用kvc 在设置model属性的时候 注意尽量不要使用基本数据类型 实例 数据模拟 注意age是null类型的 Person h import
  • iOS架构-组件化(项目框架搭建2)

    静态库引用静态库 如果像上图一样 直接在业务层组件引用数据层组件的文件 则会报错 因为组件之间没有建立引用关系 如下图 静态库如何引用Pods第三方库 拷贝Podfile文件到项目 打开终端执行pad install 直接引用Pod下面的Y

随机推荐

  • MapReduce框架原理之ReduceTask工作机制

    一 Reduce Task 并行度决定机制 reduce task的并行度 也就是同时开启了几个reduce task 分为两种情况 1 如果我们自己定义了分区器 我们能够确定自己的分区器能够形成几个物理分区 加入我们要生成5个分区 那么我
  • 谈谈对CAP定理的理解

    谈谈对CAP定理的理解 CAP定理的常规解释是任何分布式系统只能在一致性 Consitency 可用性 Availability 和分区容忍性 Partition Tolerance 中三选二 这个解释很让人费解 笔者在看了一些文章后谈谈我
  • 目标检测原理群100问

    qq群号 703346870 简述yolo的多尺度变换 怎样理解残差网络可以自行选择冗余层 https baijiahao baidu com s id 1609100487339160987 梯度下降的数学原理 怎样理解包围框回归 使用g
  • 后台dom拼接xml,动态显示统计图

    1 这个东西让我好生头疼 贴代码吧 2 3 两秒后模拟点击 4 setTimeout function 5 IE 6 if document all 7 document getElementById userQuery click 8 其
  • MATLAB 更改或隐藏热图(heatmap)的坐标轴刻度

    在热图中 坐标轴标签用 data表示 更改坐标轴标签 figure my matrix rand 3 heatmap my matrix Colormap parula 3 ColorbarVisible on XLabel Time YL
  • FreeRTOS-创建删除任务

    1 FreeRTOSConfig h文件 FreeRTOSConfig h配置文件作用 对FreeRTOS进行功能配置和裁剪 以及API函数的使能 相关的宏可以分为三大类 INCLUDE 配置FreeRTOS中可选的API函数 config
  • 比较器的设计

    一 1位比较器 1位比较器原理 1位比较 Xi Yi XY的第i位 大于Great Li1 Xi Yi 小于Less Li2 Xi Yi 等于Equal Li3 Xi Yi 同或 异或非 Lij 第1个下标表示位数 第2个下标表示大小关系1
  • sql语句中case when和as用法

    在sql语句里case when then else end可以当做c语言中switch case一样是分支语句 起到不同条件处理作用 而as相当于一个别名 可以给某个列或者某个表起新的名字 比如这里有个employee表 select f
  • R语言重命名数据框列名:使用plyr包的rename函数

    R语言重命名数据框列名 使用plyr包的rename函数 在R语言中 我们经常需要对数据框 data frame 的列名进行修改 修改列名可以使得数据更易读和理解 同时也有助于数据分析和可视化过程中的操作 在本文中 我们将介绍如何使用ply
  • C++基础知识 - map和multimap容器

    map multimap的简介 map是标准的关联式容器 一个map里存储的元素是一个键值对序列 叫做 key value 键值对 它提供基于key快速检索数据的能力 map中key值是唯一的 集合中的元素按一定的顺序排列 元素插入过程是按
  • python爬虫五:beautifulsoup4的安装使用

    1 bs4简介 概念 Beautiful Soup 是一个可以从HTML或XML文件中提取数据的网页信息提取库 安装 先安装它的依赖模块 lxml 再安装 bs4 pip install lxml gt pip install bs4 最基
  • 32万记录导入MSSQL,只需12.52秒,足足快了200多倍,省了一个小时干啥不好吗?

    现在云时代 大家都用上云了 现在云的带宽5M都觉得很大了 但是有大量的数据需要处理的话 按照传统的方式 上传一个32万记录的DBF 起码也得一个小时 而现在有款工具 来自ZHZ 可以节省你200多倍的时间 香不香 测试环境 win7 32位
  • Android Rxjava:最简单易懂的诠释 看这篇

    1 前言 Rxjava 具有链式调用 使用简单 事件与结果松耦合的特点 Rxjava 之所以深受欢迎它包含 非常多操作符 能通过 链式形 优雅整洁的代码几乎能实现所有的功能需求 本文特点 图多字少 逻辑简单 之前面试中被问了很多Rxjava
  • 激活函数(sigmoid、tanh、ReLU、softmax)

    文章目录 1 1 sigmoid函数 1 2 tanh函数 1 3 ReLU函数 1 4 softmax函数 激活函数在神经网络中的作用有很多 主要作用是给神经网络提供非线性建模能力 如果没有激活函数 那么再多层的神经网络也只能处理线性可分
  • 在阿里工作的日子里,我都学到了哪些东西?

    来阿里也有段时间了 这段时间学了很多东西 简单说起来 就是一个走出舒适区的过程 从一开始的新手入门 到逐渐熟悉业务和技术 再到慢慢的适应环境 胜任工作 总体来说 这几个月还是学到了很多东西 感觉成长的很快 但同时工作的压力也非常的大 总体来
  • 【翻译 + 整理】Qt样式表详解(2):属性——背景相关属性

    1 alternate background color 交替背景色 用于QAbstractItemView的子类 QColumnView QHeaderView QListView QTableView QTreeView 使用的前提是开
  • Zabbix监控部署项目

    为什么选择Zabbix Zabbix 是一个基于 WEB 界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案 zabbix 能监视各种网络参数 保证服务器系统的安全运营 并提供灵活的通知机制以让系统管理员快速定位 解决存在的各种
  • Springboot配置端口号

    springboot项目端口配置可以通过application yml或application properties指定 server port 80 或者 server port 8089 代码指定 springboot2 x以上版本Em
  • 关于AI自动写作的资料

    AI 自动写作 产品调研 第一种是AI新闻时事类写作 核心场景是在内容平台通过人 机混编的方式 机器帮助编辑 内容创作者 减少重复劳动 提高生产效率 主要调研了今日头条的xiaomingbot 腾讯的Dreamwriter 百度的writi
  • iOS架构师_消息转发机制

    1 动态方法解析 对象在收到无法处理的消息时 会调用下面的方法 前者是调用类方法时会调用 后者是调用对象方法时会调用 未实现类方法调用 BOOL resolveClassMethod SEL sel 未实现实例方法调用 BOOL resol