SEL、IMP、Method之间的关系:一个类(Class)持有一个分发表,在运行期分发消息,表中的每一个实体代表一个方法(Method),它的名字叫做选择子(SEL),对应着一种方法实现(IMP)。具体的分析如下:

参考苹果官方公开源码

objc4源码在线浏览

objc4源码下载

1、SEL

在上述苹果官网公开源码objc4的objc.h文件中,定义如下:

/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;

SEL方法选择器(翻译成中文叫做选择子或者选择器),表示一个selector的指针,代表方法的名称,仅以名字来识别。

SEL代表方法在Runtime期间的标识符。为SEL类型,虽然SEL是objc_selector结构体指针,但实际上它只是一个C字符串。

在类加载的时候,编译器会生成与方法相对应的选择子,并注册到Objective-C的Runtime运行系统。
无论什么类里,无论类是否存在依存关系,只要方法名相同,SEL就相同。

项目里的所有SEL都保存在一个NSSet集合里(NSSet集合里的元素不能重复),所以查找对应方法,只要找到对应的SEL就可以了。
SEL实际是根据方法名hash化了的字符串

SEL sel_registerName(const char *str)//向runtime system注册一个方法名。如果方法名已经注册,则放回已经注册的SEL
SEL sel_getUid(const char *str)//同上
@selector(<#selector#>)//oc编译器提供的
SEL NSSelectorFromString(NSString *aSelectorName)//OC字符串转化
SEL method_getName ( Method m );//根据Method结构体获取

SEL的操作函数

// 比较两个选择器
BOOL sel_isEqual ( SEL lhs, SEL rhs );
//判断方法名是否映射到某个函数实现上
BOOL sel_isMapped(SEL sel);

虽然SEL是方法的唯一标识,但不同的类调用名字相同的方法应该如何处理,接下来就要用到IMP

2、IMP

代码定义:

/// A pointer to the function of a method implementation.
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
#endif

可以简化为:

/// A pointer to the function of a method implementation.
typedef id (*IMP)(id, SEL , ...); 

IMP:代表函数指针,指向方法实现的首地址,即函数执行的入口。

该函数使用标准的C调用。

第一个参数指向self(它代表当前类实例的地址,如果是类则指向的是它的元类),作为消息的接受者;

第二个参数代表方法的选择子;...代表可选参数,前面的id代表返回值。
那么,XX调用了XXX方法,其参数为XX都确定下来了。

IMP的高级作用

既然上述元素都确定下来了,那么就可以直接绕过Runtime的消息传递机制,直接执行IMP指向的函数了。省去了一些列的查找,直接向对象发送消息,效率会高一些。

IMP imp_implementationWithBlock(id block)//根据代码块获取IMP,其实就是代码块与IMP关联
IMP method_getImplementation(Method m) //根据Method获取IMP
[[objc Class] instanceMethodForSelector:SEL]//根据OC方式获取IMP

获取一个方法的IMP时候可以直接调用IMP

IMP imp = method_getImplementation(Method m);
id objc = imp(id,SEL,argument);//objc用来保存方法的返回值,id表示调用这个方法的对象,SEL是Method的选择器,argument是方法的参数。

3、Method

runtime.h文件中,代码定义如下:

/// An opaque type that represents a method in a class definition.
typedef struct objc_method *Method;

objc_method结构体定义如下:

/// Method
struct objc_method {SEL method_name                          OBJC2_UNAVAILABLE;//方法名char *method_types                       OBJC2_UNAVAILABLE;//参数返回值字符串描述IMP method_imp                           OBJC2_UNAVAILABLE;//方法的实现
}    

Method:Method是一个objc_method结构体指针,该结构体中包含一个SEL和IMP。

实际上相当于在SEL和IMP之间作了一个映射。有了Method,SEL就可以找到对应的IMP,从而调用方法。对开发者来说是一种不透明的类型,被隐藏在我们平时书写的类或对象的方法背后。

method_name:方法名,类型为SEL,前面提到过相同名字的方法即使在不同类中定义,它们的方法选择器也相同。
method_types:方法类型,是个char指针,其实存储着方法的参数类型和返回值类型,即是Type Encoding编码。
method_imp:指向方法的实现,本质上是一个函数的指针,就是前面讲到的Implementation。

Method操作函数如下:

方法操作主要有以下函数:
// 添加方法
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );// 获取实例方法
Method class_getInstanceMethod ( Class cls, SEL name );// 获取类方法
Method class_getClassMethod ( Class cls, SEL name );// 获取所有方法的数组
Method * class_copyMethodList ( Class cls, unsigned int *outCount );// 替代方法的实现
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );// 返回方法的具体实现
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );// 类实例是否响应指定的selector
BOOL class_respondsToSelector ( Class cls, SEL sel );

class_addMethod的实现会覆盖父类的方法实现,但不会取代本类中已存在的实现,如果本类中包含一个同名的实现,则函数会返回NO。如果要修改已存在实现,可以使用method_setImplementation 一个Objective-C方法是一个简单的C函数,它至少包含两个参数–self和_cmd。所以,我们的实现函数(IMP参数指向的函数)至少需要两个参数

class_getInstanceMethodclass_getClassMethod函数,与class_copyMethodList不同的是,这两个函数都会去搜索父类的实现。

class_copyMethodList函数,返回包含所有实例方法的数组,如果需要获取类方法,则可以使用class_copyMethodList(object_getClass(cls), &count)(一个类的实例方法是定义在元类里面)。该列表不包含父类实现的方法。outCount参数返回方法的个数。在获取到列表后,我们需要使用free()方法来释放它。

class_replaceMethod函数,该函数的行为可以分为两种:如果类中不存在name指定的方法,则类似于class_addMethod函数一样会添加方法;如果类中已存在name指定的方法,则类似于method_setImplementation一样替代原方法的实现。

class_getMethodImplementation函数,该函数在向类实例发送消息时会被调用,并返回一个指向方法实现函数的指针。这个函数会比method_getImplementation(class_getInstanceMethod(cls, name))更快。返回的函数指针可能是一个指向runtime内部的函数,而不一定是方法的实际实现。例如,如果类实例无法响应selector,则返回的函数指针将是运行时消息转发机制的一部分。

class_respondsToSelector函数,我们通常使用NSObject类的respondsToSelector:或instancesRespondToSelector:方法来达到相同目的。

参考文章

SEL、Method和IMP区别

深入探究SEL,Method,IMP

iOS-Runtime之SEL、IMP、Method相关推荐

  1. iOS runtime再学习

    iOS面试专题一 几乎是默写出来,加上自己理解的博客(iOS面试) 持续更新中... 问题:当方法转发到另一个类的对象的时候,另一个类没有对应的属性怎么办,会崩溃吗? 文章目录 1.基础数据结构 2. ...

  2. ios runtime重要性_iOS:学习runtime的理解和心得

    作者:兴宇是谁 授权本站转载. Runtime是想要做好iOS开发,或者说是真正的深刻的掌握OC这门语言所必需理解的东西.最近在学习Runtime,有自己的一些心得,整理如下, 一为 查阅方便 二为 ...

  3. ios runtime重要性_iOS 之runtime运行机制理解

    Runtime 是想要做好iOS 开发,或者说是真正的深刻的掌握OC这门语言所必须的理解的东西,最近在学习Runtime. 查阅方便 或许能给他人一些一些启发 什么是Runtime 我们写的代码在程序 ...

  4. ios runtime详解

    移动开发 Web前端 架构设计 编程语言 互联网 数据库 系统运维 云计算 研发管理 综合 netfoucs.com核心网络 iOS_运行时runtime 最终效果图: 打开XCode帮助文档,搜索O ...

  5. iOS runtime 学习分享

    这是团队小伙伴在内部的一次技术分享, 很开心, 我们团队越来越好了. iOS runtime 学习分享 Author:Liao Zusheng 申明: 部分资料来自于知名论坛和博客,已在文中给出相关源 ...

  6. iOS runtime 底层详解、内部原理、场景应用

    前言学:位域和共用体 一:isa指针--runtime之前的学习 1.1:苹果应用的按位或.按位与 二:类对象信息 2.1:类对象信息:rw_t 2.2:类对象信息:方法缓存(很关键) 2.2:类对象 ...

  7. iOS runtime实战应用:关联对象

    在开始之前建议先阅读iOS runtime的基础理解篇:iOS内功篇:runtime 有筒子在面试的时候,遇到这样一个问题:"如何給NSArray添加一个属性(不能使用继承)",筒 ...

  8. iOS中的SEl和IMP到底是什么

    SEL : 类成员方法的指针,但不同于C语言中的函数指针,函数指针直接保存了方法的地址,但SEL只是方法编号. IMP:一个函数指针 IMP和SEL关系 每一个继承于NSObject的类都能自动获得r ...

  9. iOS总结-Runtime篇之黑魔法Method Swizzling的滥用会有危险吗

    参考https://www.jianshu.com/p/19c5736c5d9a, http://blog.sina.com.cn/s/blog_a343f32b0101en4o.html runti ...

  10. iOS runtime和runloop

    runtime 和 runloop 作为一个程序员进阶是必须的,也是非常重要的, 在面试过程中是经常会被问到的, 所以大家有必要进行研究,有能力的童鞋可以和下面作者一样, 亲历实践一下. 在简书里发现 ...

最新文章

  1. 如何在sqlite3连接中创建并调用自定义函数
  2. iOS 9 学习系列:Xcode Code Coverage Tools
  3. telnet远程登陆、mstsc远程控制、SSH之间的比较和区别
  4. php生成网页缩略图接口,php生成网站缩略图
  5. 【英语学习】【加州教材】【G1】【科学】Science目录及术语表
  6. JavaScript事件与处理程序绑定(1)
  7. 如何打造7*24h持续交付通道?阿里高级技术专家的5点思考
  8. 计算机网络图标打不开怎么回事,双击打不开图标怎么办 双击打不开图标解决方法【详解】...
  9. MODLE CODE
  10. java版我的世界光追,光追有多神奇?我的世界VS别人的世界
  11. iOS查询iTunes中国商店的APP信息
  12. 背景减除算法之K-Nearest(KNN)和Mixture of Gaussians(MOG2)
  13. 小米4c如何添加语言,小米4C输入法怎么切换 小米4C输入法切换教程
  14. 其他浏览器(firefox,chrome)可以上网 ie(Internet Explorer)无法上网 解决方法
  15. 有赞商城如何对接ERP、CRM系统?
  16. python如何绘制两点间连线_如何用 Python 绘制玫瑰图等常见疫情图
  17. java毕业生设计寻艺画室网站计算机源码+系统+mysql+调试部署+lw
  18. html+css+JavaScript最最最简易图片放大器——随手练
  19. 复工别慌,这里有 24 个渠道可以买到口罩
  20. 如何进行批量导入通讯录,简单易学

热门文章

  1. Java Attach机制
  2. 饥荒控制台输入没用_饥荒联机版代码怎么用 代码输入没用解决方法
  3. 抖音很火的小程序表白html,最近抖音很火的表白小程序写法C#版
  4. win10资源管理器频繁重启可能原因及解决方案
  5. C++中的悬垂指针(delete指针后依然可以访问的问题)
  6. C++作业之模拟打牌:小喵钓鱼
  7. 安全专业委员会发言_企业安全委员会发言
  8. Asp.Net MVC4.0 官方教程 入门指南之六--查看Edit方法和Edit视图
  9. Dracena:实时数字孪生平台
  10. 【每日一题】递增序列中绝对值最小的数