【iOS】 消息传递和消息转发

news2024/11/13 21:45:27

消息传递和消息转发

    • objc_msgSend执行流程
    • 消息发送
    • 动态方法解析
    • 消息转发
    • super
    • 面试题

objc_msgSend执行流程

OC中的方法调用,其实都是转化为objc_msgSend函数调用,objc_msgSend的执行流程可以分为3大阶段

    1. 消息发送
    1. 动态方法解析
    1. 消息转发

消息发送

在这里插入图片描述

消息发送流程是我们平时最经常使用的流程,其他的像动态方法解析和消息转发其实是补救措施。具体流程如下

1、首先判断消息接受者receiver是否为nil,如果为nil直接退出消息发送
2、如果存在消息接受者receiverClass,首先在消息接受者receiverClass的cache中查找方法,如果找到方法,直接调用。如果找不到,往下进行
3、没有在消息接受者receiverClass的cache中找到方法,则从receiverClass的class_rw_t中查找方法,如果找到方法,执行方法,并把该方法缓存到receiverClass的cache中;如果没有找到,往下进行
4、没有在receiverClass中找到方法,则通过superClass指针找到superClass,也是现在缓存中查找,如果找到,执行方法,并把该方法缓存到receiverClass的cache中;如果没有找到,往下进行
5、没有在消息接受者superClass的cache中找到方法,则从superClass的class_rw_t中查找方法,如果找到方法,执行方法,并把该方法缓存到receiverClass的cache中;如果没有找到,重复4、5步骤。如果找不到了superClass了,往下进行
6、如果在最底层的superClass也找不到该方法,则要转到动态方法解析

动态方法解析

在这里插入图片描述

把这两个方法名记住:+resolveInstanceMethod: +resolveClassMethod:

  • 开发者可以实现以下方法,来动态添加方法实现
    • +resolveInstanceMethod:
    • +resolveClassMethod:
  • 动态解析过后,会重新走“消息发送” 的流程,从receiverClass的cache中查找方法这一步开始执行

+ (BOOL)resolveInstanceMethod:(SEL)sel {  //sel代表无法响应的方法名
    if (sel == @selector(test)) {
        //获取其他方法
        Method method = class_getInstanceMethod([self class], @selector(other));  //这是一个runtime函数,需要包含头文件#import <objc/runtime.h>,
            //参数一:(class)sel是未能响应的方法的类,就传[self class]
            //参数二(SEL)name是要查找的方法名(就是自己动态添加的方法的方法名),传 @selector(方法名)
        //动态添加test的方法
        class_addMethod([self class], sel, method_getImplementation(method), method_getTypeEncoding(method));//这也是一个runtime函数,用于动态的向一个类添加一个新的方法。
        //参数一:(Class)cls是要添加方法的类,就传[self class]
        //参数二:(SEL)name表示未能相应的方法名,就传sel
        //参数三:(IMP)imp是方法的实现函数指针, 就传method_getImplementation(method)
        //参数四:(const char*)types是方法的类型编码字符串,就传method_getTypeEncoding(method))
    }
    return [super resolveInstanceMethod:sel];
} //系统默认返回NO

可以看出,这个方法的实现大部分内容都是固定的。完全套模版。

如果这个方法没有实现,默认返回NO,并查看有没有实现forwardingTargetForSelector:方法

消息转发

如果一个方法在消息发送阶段没有找到相关方法,也没有进行动态方法解析,这个时候就会走到消息转发阶段了。
在这里插入图片描述

(==再记住下面这三个方法:forwardingTargetForSelector , methodSignatureForSelectot , forwardInvocation: ,doesNotRecognizeSelector: ==)

  • 调用forwardingTargetForSelector,返回值不为nil时,会调用objc_msgSend(返回值, SEL)
  • 调用methodSignatureForSelector,返回值不为nil,调用forwardInvocation:方法;返回值为nil时,调用doesNotRecognizeSelector:方法
  • 开发者可以在forwardInvocation:方法中自定义任何逻辑
  • 以上方法都有对象方法、类方法2个版本(前面可以是加号+,也可以是减号-)

- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(test)) {
        return [[Student alloc] init];
    }
    return nil;
} //系统默认返回nil
//调用forwardingTargetForSelector,返回值不为nil时,会调用objc_msgSend(返回值, SEL),结果就是调用了objc_msgSend(Student,test)

这里我的理解就是,把这个方法换一个对象来调用,调用成功的前提是,该对象的类实现了此方法名的方法

forwardingTargetForSelector如果没有实现,默认返回nil。进入后续的方法。


- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(test)) {
        
        //这三种实现方法都可以
        return [[[Student alloc] init] methodSignatureForSelector:aSelector];
        //return [[Student class] instanceMethodSignatureForSelector:aSelector];
        //return [NSMethodSignature signatureWithObjCTypes:"i@:i"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {

    if ([anInvocation selector] == @selector(test)) {

    } else {

    }

    NSLog(@" 直接在这里写方法实现,这里我想干嘛就干嘛");
}

forwardingTargetForSelector:返回nil,才会进入这一步。
如果methodSignatureForSelector: 获取方法签名成功,则调用forwardInvocation:来转发消息,如果失败,就是经典的doesNotRecognizeSelector:报错
forwardInvocation:方法的使用非常灵活

anInvocation 参数是一个 NSInvocation 对象,它封装了一个方法调用的所有信息,包括:

  • 目标对象 (即将被调用方法的对象)
  • 方法选择器 (即将被调用的方法)
  • 方法参数 (调用方法时传递的参数)
  • 返回值 (方法的返回值)

例如,你可以使用以下方法获取方法选择器和参数:

SEL theSelector = [anInvocation selector];
const char *methodType = [anInvocation methodSignature].methodReturnType;

你还可以设置新的目标对象和参数,然后调用 invokeWithTarget: 方法将消息转发给另一个对象:


[anInvocation setTarget:anotherObject];
[anInvocation setArgument:&someArgument atIndex:2];
[anInvocation invoke];

通过这种方式,你可以将收到的消息转发给其他对象来处理。这在实现动态消息转发的时候非常有用。

另外,anInvocation 对象还提供了一些其他有用的方法,比如 getReturnValue: 和 getArgument:atIndex: 等,可以帮助你获取和设置方法的返回值和参数。

super

待补充

面试题

  1. 什么是消息转发?它是如何工作的?简要回答。

答:消息转发是Objective-C处理未识别消息的机制

当对象无法响应某消息时,会进入消息转发流程:
1. 动态方法解析:通过实现+resolveInstanceMethod:或+resolveClassMethod:动态添加方法。
2. 备用接收者:通过-forwardingTargetForSelector:指定另一个对象处理消息。
3. 完整消息转发:通过-methodSignatureForSelector:和-forwardInvocation:完整转发消息。

  1. 什么是Objective-C中的消息传递?与C++中 的方法调用有什么区别?底层实现过程?

答:

  • 在Objective-C中,消息传递是对象间通信的方式。发送消息的语法为[object message],底层实现是将消息发送给对象的isa指针指向的类,在方法列表中查找对应的方法实现。
  • 与C++中的方法调用区别:
    Objective-C通过运行时系统实现消息传递,方法绑定在运行时完成。
    C++通过编译时绑定(静态绑定),方法在编译时确定。
  • 底层实现过程:
    消息传递底层实现通过objc_msgSend函数:
      1. 查找方法:根据对象的isa指针,找到类的method_list,查找对应的SEL(选择器)。
      1. 执行方法:找到方法实现后,执行该方法。如果找不到,进入消息转发机制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1950909.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

情绪稳定的人有什么特点?

第一部分&#xff1a;至纯之人&#xff0c;大器晚成 1.1 单纯&#xff0c;不是天真 你知道吗&#xff1f;那些能够成就大事的人&#xff0c;往往在人性上非常单纯。他们对外界的需求很低&#xff0c;更多的是向内寻求。这样的人&#xff0c;他们的内心世界像一片净土&#xff…

Internet Download Manager(IDM)6.43免费试用体验版下载

1. Internet Download Manager&#xff08;IDM&#xff09;是一款功能强大的下载管理器&#xff0c;能够将下载速度提高多达5倍。 2. IDM具备多线程下载、断点续传、自动捕获链接等特性。 IDM马丁正版下载如下: https://wm.makeding.com/iclk/?zoneid34275 idm最新绿色版一…

HarmonyOS 核心功能:一多特性

简述定义和目标&#xff0c;分述界面级&#xff08;核心&#xff09;、功能级、工程级的一多开发 定义&#xff1a; 一套代码&#xff0c;一次开发&#xff0c;多端按需部署 目标&#xff1a;支持开发者快速开发多设备上的应用 一 界面级一多开发&#xff08;重点&#xf…

宝塔单ip,新建多站点

报错如上&#xff1a; 那么如何新建多站点呢 先随便写个名字上去&#xff0c;然后再重新绑定别的端口… 这个时候访问99端口即可 。 如果是有域名&#xff0c;则不需要这样做 、直接80端口也可以多站点

FPGA:有限状态机

从以下6个实验理解状态机的概念 开发板频率为 50 M H z 50MHz 50MHz&#xff0c;一个时钟周期是 20 n s 20ns 20ns。 1、实验一:LED灯亮0.25秒、灭0.75秒的状态循环 通过之前的分析&#xff0c;我们实现频闪灯时&#xff0c;是让led灯在0.5秒实现一次翻转&#xff0c;而这里…

《Cross-Modal Dynamic Transfer Learning for Multimodal Emotion Recognition》

Multi-modal系列论文研读目录 文章目录 Multi-modal系列论文研读目录1.ABSTRACT2.INDEX TERMS3.INTRODUCTION4.RELATED WORKSA. MULTIMODAL EMOTION RECOGNITION 多模态情感识别1) CONVENTIONAL FUSION METHODS 常规融合方法2) TRANSFORMER-BASED FUSION METHODS 基于变压器的融…

Redis (常用数据结构和命令)

目录 简介 概述 特点 数据结构 常用命令 通用命令 keys del exists expire 与 ttl String 命令 SET 和GET: MSET和MGET INCR和INCRBY和DECY SETNX SETEX Redis 命令 Key 的层级结构 key层级关系 &#xff1a; Hash命令 HSET和HGET HMSET和HMGET HGETALL H…

MySQL练手 --- 1141. 查询近30天活跃用户数

题目链接&#xff1a;1141. 查询近30天活跃用户数 思路&#xff1a; 题目要求&#xff1a;统计截至 2019-07-27&#xff08;包含2019-07-27&#xff09;&#xff0c;近 30 天的每日活跃用户数&#xff08;当天只要有一条活动记录&#xff0c;即为活跃用户&#xff09; 要计算…

前端模块化CommonJS、AMD、CMD、ES6

在前端开发中&#xff0c;模块化是一种重要的代码组织方式&#xff0c;它有助于将复杂的代码拆分成可管理的小块&#xff0c;提高代码的可维护性和可重用性。CommonJS、AMD&#xff08;异步模块定义&#xff09;和CMD&#xff08;通用模块定义&#xff09;是三种不同的模块规范…

H3CNE(OSPF动态路由)

目录 7.1 静态路由的缺点与动态路由分类 7.1.1 静态路由的缺点 7.1.2 动态路由的分类 7.2 OSPF基础 7.2.1 OSPF的区域 ​编辑 7.2.2 Router-id 7.2.3 开销-Cost or Metric 7.2.4 路由转发 7.3 OSPF邻居表建立过程 7.3.1 五种包 7.3.2 建立邻居表的第一步 7.3.3 邻居建立…

数据结构与算法--顺序表(Java)

&#x1f4dd;个人主页&#x1f339;&#xff1a;誓则盟约 ⏩收录专栏⏪&#xff1a;Java SE &#x1f921;往期回顾&#x1f921;&#xff1a;Java SE--基本数据类型&#xff08;详细讲解&#xff09; &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 什么…

前端养成记-实现一个低配版简单版本的vue3表单自定义设计组件

简介&#xff1a; 通过使用了最新的vue3,vite2,TypeScript等主流技术开发&#xff0c;并配合使用vuedraggable 插件以及antd design vue 组件库实现低配版本的自定义表单设计组件&#xff1b; 项目地址&#xff1a;https://gitee.com/hejunqing/vue3-antdv-generator

GLSL教程 第8章:几何着色器

目录 8.1 几何着色器的介绍 几何着色器的主要功能&#xff1a; 几何着色器的工作流程&#xff1a; 8.2 实现基本的几何变换 示例&#xff1a;将三角形扩展成多个三角形 8.3 几何着色器的高级应用 1. 粒子系统 2. 光晕效果 3. 线框模型 小结 几何着色器是图形管线中的一…

Linux——管理本地用户和组(详细介绍了Linux中用户和组的概念及用法)

目录 一、用户和组概念 &#xff08;一&#xff09;、用户的概念 &#xff08;二&#xff09;、组的概念 补充组 主要组 二、获取超级用户访问权限 &#xff08;一&#xff09;、su 命令和su -命令 &#xff08; 二&#xff09;、sudo命令 三、管理本地用户账户 &…

Java面试八股之什么是声明式事务管理,spring怎么实现声明式事务管理?

什么是声明式事务管理&#xff0c;spring怎么实现声明式事务管理&#xff1f; 声明式事务管理是一种编程范式&#xff0c;它允许开发人员通过声明性的配置或注解&#xff0c;而不是硬编码事务处理逻辑&#xff0c;来指定哪些方法或类应该在其上下文中执行事务。这种方法将事务…

Kadane 算法 | 53. 最大子数组和 + 918. 环形子数组的最大和

目录 1 维基百科2 53. 最大子数组和2.1 代码思路2.2 完整代码 3 918. 环形子数组的最大和3.1 代码思路3.2 完整代码 1 维基百科 最大子数组问题 在计算机科学中&#xff0c;最大子数组问题的目标是在数组的一维方向找到一个连续的子数组&#xff0c;使该子数组的和最…

Axious的请求与响应

Axious的请求与响应 1.什么是Axious Axious是一个开源的可以用在浏览器和Node.js的异步通信框架&#xff0c;它的主要作用就是实现AJAX异步通信&#xff0c;其功能特点如下&#xff1a; 从浏览器中创建XMLHttpRequests ~从node.js创建Http请求 支持PromiseAPI 拦截请求和…

[UVM源代码研究] 聊聊UVM中的callback机制

1. callback机制是什么&#xff1f; 以最高效的方式完成芯片验证&#xff0c;一直以来都是验证人员的首要目标&#xff0c;那么最直接的方式就是环境的移植和重用&#xff0c;一个优秀的验证工程师&#xff0c;在开发环境的过程中&#xff0c;一定会考虑环境的继承和重用。 继…

c++ 智能指针shared_ptr与make_shared

shared_ptr是C11引入的一种智能指针&#xff0c;‌它允许多个shared_ptr实例共享同一个对象&#xff0c;‌通过引用计数来管理对象的生命周期。‌当最后一个持有对象的shared_ptr被销毁时&#xff0c;‌它会自动删除所指向的对象。‌这种智能指针主要用于解决资源管理问题&…

简单小案例分析

一、容器和实例关系 <div class"app"><h1>Hello,{{name}}</h1> </div> <div class"app"><h1>Hello,{{name}}</h1> </div><script>//创建Vue实例new Vue({el:".app", //el用于指定当前V…