iOS-Runtime之SEL、IMP、Method
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_getInstanceMethod、class_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相关推荐
- iOS runtime再学习
iOS面试专题一 几乎是默写出来,加上自己理解的博客(iOS面试) 持续更新中... 问题:当方法转发到另一个类的对象的时候,另一个类没有对应的属性怎么办,会崩溃吗? 文章目录 1.基础数据结构 2. ...
- ios runtime重要性_iOS:学习runtime的理解和心得
作者:兴宇是谁 授权本站转载. Runtime是想要做好iOS开发,或者说是真正的深刻的掌握OC这门语言所必需理解的东西.最近在学习Runtime,有自己的一些心得,整理如下, 一为 查阅方便 二为 ...
- ios runtime重要性_iOS 之runtime运行机制理解
Runtime 是想要做好iOS 开发,或者说是真正的深刻的掌握OC这门语言所必须的理解的东西,最近在学习Runtime. 查阅方便 或许能给他人一些一些启发 什么是Runtime 我们写的代码在程序 ...
- ios runtime详解
移动开发 Web前端 架构设计 编程语言 互联网 数据库 系统运维 云计算 研发管理 综合 netfoucs.com核心网络 iOS_运行时runtime 最终效果图: 打开XCode帮助文档,搜索O ...
- iOS runtime 学习分享
这是团队小伙伴在内部的一次技术分享, 很开心, 我们团队越来越好了. iOS runtime 学习分享 Author:Liao Zusheng 申明: 部分资料来自于知名论坛和博客,已在文中给出相关源 ...
- iOS runtime 底层详解、内部原理、场景应用
前言学:位域和共用体 一:isa指针--runtime之前的学习 1.1:苹果应用的按位或.按位与 二:类对象信息 2.1:类对象信息:rw_t 2.2:类对象信息:方法缓存(很关键) 2.2:类对象 ...
- iOS runtime实战应用:关联对象
在开始之前建议先阅读iOS runtime的基础理解篇:iOS内功篇:runtime 有筒子在面试的时候,遇到这样一个问题:"如何給NSArray添加一个属性(不能使用继承)",筒 ...
- iOS中的SEl和IMP到底是什么
SEL : 类成员方法的指针,但不同于C语言中的函数指针,函数指针直接保存了方法的地址,但SEL只是方法编号. IMP:一个函数指针 IMP和SEL关系 每一个继承于NSObject的类都能自动获得r ...
- iOS总结-Runtime篇之黑魔法Method Swizzling的滥用会有危险吗
参考https://www.jianshu.com/p/19c5736c5d9a, http://blog.sina.com.cn/s/blog_a343f32b0101en4o.html runti ...
- iOS runtime和runloop
runtime 和 runloop 作为一个程序员进阶是必须的,也是非常重要的, 在面试过程中是经常会被问到的, 所以大家有必要进行研究,有能力的童鞋可以和下面作者一样, 亲历实践一下. 在简书里发现 ...
最新文章
- 如何在sqlite3连接中创建并调用自定义函数
- iOS 9 学习系列:Xcode Code Coverage Tools
- telnet远程登陆、mstsc远程控制、SSH之间的比较和区别
- php生成网页缩略图接口,php生成网站缩略图
- 【英语学习】【加州教材】【G1】【科学】Science目录及术语表
- JavaScript事件与处理程序绑定(1)
- 如何打造7*24h持续交付通道?阿里高级技术专家的5点思考
- 计算机网络图标打不开怎么回事,双击打不开图标怎么办 双击打不开图标解决方法【详解】...
- MODLE CODE
- java版我的世界光追,光追有多神奇?我的世界VS别人的世界
- iOS查询iTunes中国商店的APP信息
- 背景减除算法之K-Nearest(KNN)和Mixture of Gaussians(MOG2)
- 小米4c如何添加语言,小米4C输入法怎么切换 小米4C输入法切换教程
- 其他浏览器(firefox,chrome)可以上网 ie(Internet Explorer)无法上网 解决方法
- 有赞商城如何对接ERP、CRM系统?
- python如何绘制两点间连线_如何用 Python 绘制玫瑰图等常见疫情图
- java毕业生设计寻艺画室网站计算机源码+系统+mysql+调试部署+lw
- html+css+JavaScript最最最简易图片放大器——随手练
- 复工别慌,这里有 24 个渠道可以买到口罩
- 如何进行批量导入通讯录,简单易学
热门文章
- Java Attach机制
- 饥荒控制台输入没用_饥荒联机版代码怎么用 代码输入没用解决方法
- 抖音很火的小程序表白html,最近抖音很火的表白小程序写法C#版
- win10资源管理器频繁重启可能原因及解决方案
- C++中的悬垂指针(delete指针后依然可以访问的问题)
- C++作业之模拟打牌:小喵钓鱼
- 安全专业委员会发言_企业安全委员会发言
- Asp.Net MVC4.0 官方教程 入门指南之六--查看Edit方法和Edit视图
- Dracena:实时数字孪生平台
- 【每日一题】递增序列中绝对值最小的数