SEL selector (二)

SEL消息机制工作原理是什么 

引用下面文章:

 

我们在之前有提到,一个类就像一个 C 结构.NSObject 声明了一个成员变量: isa. 由于 NSObject 是所有类的根类,所以所有的对象都会有一个 isa 的成员变量[公共继承].而该 isa 变量指向该对象的类(图3.15)[类在Objective-C中也是一个实体, 由于存在Objective-C 运行环境所有的类将有自己的存储空间.Objective-C 运行环境将为每个类分配空间. 这里 所说的 isa,正是指向这样一个类的空间. 从而建立类和对象之间的对应关系.] 类空间 包含了该类定义的成员变量,以及方法实现, 还包含了指向自己父类空间的指针. 

 

 

方法以 selector 作为索引. selector 的数据类型是 SEL. 虽然 SEL 定义成 char*, 我们可 以把它想象成 int. 每个方法的名字对应一个唯一的 int 值.比如, 方法 addObject: 可能 对应的是 12. 当寻找该方法是, 使用的是 selector,而不是名字 @"addObject:"

Objective-C 数据结构中,存在一个 name - selector 的映射表如图 3.16 

 

 

在编译的时候, 只要有方法的调用, 编译器都会通过 selector 来查找,所以 (假设 addObject 的 selector 为 12)

 [myObject addObject:yourObject]; 

将会编译变成

objc_msgSend(myObject, 12, yourObject);

这里,objec_msgSend()函数将会使用 myObjec 的 isa 指针来找到 myObject 的类空间结构并 在类空间结构中查找 selector 12 所对应的方法.如果没有找到,那么将使用指向父类的指 针找到父类空间结构进行 selector 12 的查找. 如果仍然没有找到,就继续往父类的父类一 直找,直到找到为止, 如果到了根类 NSObject 中仍然找不到,将会抛出异常.

我们可以看到, 这是一个很动态的查找过程.类的结构可以在运行的时候改变,这样可以很 容易来进行功能扩展[Objective-C 语言是动态语言, 支持动态绑定.

 

再来看

Objective-C如何获取消息的原理详解文章

Objective-C获取消息工作原理是本文要介绍的内容,看name mangling的时候,也讲到了Objective-C的name mangling,于是又重新读了一下Objective-C 2.0 programming Language以及Objective-C 2.0 Runtime Reference里的相关内容,自己归纳一下。

先贴一段代码:

 

[plain] view plaincopy
  1. MyClass.h    
  2.    @interface MyClass : NSObject    
  3.    {    
  4.     }    
  5.    @end    
  6.    MyClass.m    
  7.    #import    
  8.    #import “MyClass.h”    
  9.    void myClassIMP(id _rec, SEL _cmd, int theInt)    
  10.    {    
  11.       NSLog(@”dynamic added method:%d”,theInt);    
  12.    }    
  13.       
  14. - (id)init    
  15. {    
  16.     if( ( self = [super init]) != nil )    
  17.     {    
  18.    class_addMethod([MyClass class], @selector(dynGeneratedMethod:),(IMP)myClassIMP,”v@:i”);    
  19.      }    
  20.     return self;    
  21. }    
  22.     
  23. Main.c    
  24. #import “MyClass.h”    
  25. int main(int argc, char *argv[])    
  26. {    
  27.   MyClass theInstance = [[MyClass alloc] init];    
  28.   [theInstance dynGeneratedMethod:10];    
  29.  return 0;    
  30. }  

这段代码执行的结果是在控制台上输出:

 

dynamic added method:10

 

接着来详细分析一下上面的代码:

在ObjC的类中这样的一个声明 – (void)foo:(int)a;被称作方法(method),而在调用的地方: [theClass foo:10];则被称之为发送消息(send message),具体来说是给对象theClass 发送foo:消息,注意这里foo后面的”:”,它也是消息名称的一部分,最前面的'-'代表实例方法,'+'代表类方法。而类似的语句,在C或C++ 中,通常被称为呼叫函数(call function),在ObjC中,函数(function)一词很少用到,不是它不存在,而是它被ObjC runtime给隐藏了起来。

如前所述,ObjC是以消息机制来工作的,但其实诸如-(void)foo:(int)a的语句在编译时被 objc_msgSend(receiver,selector,arg1,arg2,….)替换了,所以其实每一条发送消息的代码本质上还是调用函数 (call function),不过他们调用的都是同一个函数objc_msgSend(也可能是objc_msgSend_stret(返回值是结构 体),objc_msgSend_fpret(返回值是浮点型)等)

分析objc_msgSend的参数,第一个receiver的类型是id,代表接受消息的对象,第二个是selector代表接收对象的方法,后面的是该方法的参数,之前那条语句的被编译器替换后就是:

[theClass foo:10]  -> objc_msg(theClass,@selector(foo:),10);

 

 

因为消息的接受对象和接受对象的方法都参数化,所以在运行时刻,接受对象和接受对象的方法都可以是动态的!

比如说程序里面可以这样写:

id helper = getTheReceiver(); 
SEL request = getTheSelector(); 
[helper performSelector:request];

它的实现是基于ObjC runtime. NSObject类实现了这套机制,所以每一个继承于NSObject的类都能自动获得runtime的支持。在这样的一个类中,有一个isa指针,指向 该类定义的数据结构体,这个结构体是由编译器编译时为类(须继承于NSObject)创建的.在这个结构体中有包括了指向其父类类定义的指针以及 Dispatch table. Dispatch table是一张SEL和IMP的对应表。

对于名称相同的方法,他们都有相同的SEL,方法的名称不包括类名称,所以子类和父类中的同名方法拥有相同的SEL,但是他们的实现可以各不相同, 因而在他们各自的Dispatch表中SEL所对应的IMP是不同的,IMP是一个函数指针,而虽然每一个SEL对应的是一个方法的名称,但考虑到效 率,SEL本身是一个整型,编译器会另外生成一张SEL和方法名称对应的表。有了这样的结构,objc就可以实现多态了。还是这行代码:

[theClass foo:10];

是向theClass发送了foo:消息,那么首先在theClass的类结构的Dispatch table里找有没有对应的SEL,如果有的话,就表示theClass有响应该消息的方法,程序就跳到该方法的代码地址头(由IMP指定),开始执行。 如果在theClass的Dispatch table找不到对应的SEL,那么就会通过isa所指的结构体中包含的父类指针,到父类里面去寻找,如果到最后还是没有找到,就会出现runtime error.所以说,即使theClass以及它的父类都没有定义-(void) foo:(int)a方法,程序还是可以通过编译,但如果是用xcode的话,编译器会有警告,告知theClass可能无法响应该消息。不会报错的原因 是类的方法也可以在执行时刻创建!上面的代码:

class_addMethod([MyClass class], @selector(dynGeneratedMethod:),(IMP)myClassIMP,”v@:i”);

就是给MyClass类在执行时刻增加了一个响应dynGeneratedMethod:消息的方法,这样之后对任何MyClass的instance类 发送dynGeneratedMethod:消息,就会得到响应了.myClassIMP是类收到该消息时要调用的方法,其声明如下:

void myClassIMP(id _rec, SEL _cmd, int theInt)

 

这个方法的前面两个参数是必须的,之后的参数才是我们实际用到的参数,数目和@selector()中的冒号数一样,冒号数代表的就是参数个数。第一个参数是消息的接受对象,是MyClass的实例,第二个参数是由SEL代表的具体消息。

Class_addMethod的最后一个参数是表示dynGeneratedMethod:的返回值和参数信息,不过我自己试了一下,这个参数不起作用。

几个要点:

1、对于C中被称为函数(function)和函数调用(function call)的地方,在ObjC中被叫做方法(method)和发送消息(send message).试图调用未定义的方法会导致编译错误,而发送一条消息,即使没有任何类定义了响应该消息的方法,编译时也不会报错,从语义上讲这也是对 的,发一条消息本来就不要求一定有人会响应,不过如果执行到发送消息的代码时真的没有类可以响应的话,是会发生runtime error,为了避免这种事情发生,可以先进行检测,这样写

if( [myClass respondsToSelector:@selector(foo:)]) 
   [myClass foo:10]; 
}

我感觉ObjC这样的一套sender receiver的定义更注重面向对象的概念。类是一个接收者(receiver),如果定义了某个方法,就可以接收和这个方法名称相同的消息。而使用该 类的client(sender),则尝试向该类发送消息.如果匹配了,就跳到类的方法里执行。

2、方法名称是诸如foo:,不包括返回类型,参数类型,而又因为一个foo:对应于一个SEL,所以说ObjC不支持相同的foo:有不同的返回 类型,也不支持重载。不过类方法和实例方法可以有相同的名字,而又有不同类型的参数和返回类型,因为它们不是处在同一张dispatch table中。

3、不仅类的方法可以运行时刻创建,类本身也可以在运行时刻创建,前面提到继承于NSObject的类,编译器会帮忙生成ObjC runtime所需要的类结构定义,只要我们在代码里也按照那个结构创建了自己的类,那一样可以获得ObjC runtime的支持。

转载于:https://www.cnblogs.com/idLuffy/p/4036514.html

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

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

相关文章

mobile cpu上禁用alpha test的相关总结

因为,每家芯片的特性不同,根据向framebuffer写法的不同,分为tile-based的mobile cpu,如ImgTec PowerVR,ARM Mali,一部分老版本Qualcomm Adreno。还有标准的direct(immediate)的mobil…

达梦定时迁移数据

1. 生成迁移源代码 1.1 启动DM迁移工具(bin/dts.exe) 1.2 右击迁移管理空白处 -> 新建工程 1.3 展开工程 -> 右击迁移,新建迁移 -> 输入迁移名称,确认 1.4 右击迁移名称,打开 -> 输入源数据库连接信息&…

JSP教程–最终指南

编者注: JavaServer Pages(JSP)技术使您可以轻松创建同时包含静态和动态组件的Web内容。 JSP技术提供了Java Servlet技术的所有动态功能,但提供了一种更自然的方法来创建静态内容。 JSP技术的主要功能包括用于开发JSP页面的语言&…

tongweb6数据源使用中时常报空异常处理方式

1.在tongweb控制台 -> jdbc配置中设置数据源参数 1.1 勾选空闲超时,时间默认 1.2 勾选泄露超时时间 ,时间为半天(14400) 1.3 勾选连接有效性检查、创建连接验证、获取连接验证、归还连接验证 图中设置泄露超时时间为900…

eclipse远程tomcat javaweb debug样例(windows)

1.tomcat配置可被远程debug端口参数 catalina.bat 中添加 set CATALINA_OPTS-Xdebug -agentlib:jdwptransportdt_socket,servery,suspendn,address8000 导出项目war包到tomcat/webapps/目录下 切换到tomcat/bin目录下 双击startup.bat启动运行项目 2.eclipse中启动远程debug…

ASP.NET MVC的ContentResult

ASP.NET MVC的ContentResult返回简单的纯文本内容,可通过ContentType属性指定应答文档类型,通过ContentEncoding属性指定应答文档的字符编码。一个例子来演习,自定义一个RwResult,它继承ContentResult,为视图象ASP.NET…

windows搜索指定目录下包含某个字符串的文件

1.打开cmd窗口 :winr 快捷键-> 输入cmd 回车 2.切换到被搜索的文件夹(E:\shgwy文档\日常\更新\20220808)下 如输入: cd E:\shgwy文档\日常\更新\20220808 e: 3.输入搜索命令 c:\Windows\System32\findstr.exe /s /i "wa…

IIS7日志文件位置

准备统计下页面访问量 查找IIS日志,发现在以前IIS6日志的位置,竟然木有找到日志... 查看下IIS设置,发现IIS7和6的默认日志位置不一样额... IIS 6 Log files location IIS 6中日志文件的位置 %windir%\System32\LogFiles IIS 7 Log files location IIS的日…

jwt重放攻击_4个点搞懂JWT、JWS、JWE

1.JWT是何物,有哪些常用的场景JWT(json web token)是设计一种简洁,安全,无状态的token的实现规范rfc7519,通常用于网络请求方和网络接收方之间的网络请求认证。jwt的常用场景1.1: restful api接口的无状态认证, 在传统的web应用中…

Verification Mind Games---how to think like a verifier像验证工程师一样思考

1. 有效的验证需要验证工程师使用不同于设计者的思维方式思考问题。具体来说,验证更加关心在严格遵循协议的基础上发现设计里面的bug,搜索corner cases,对设计的不一致要保持零容忍的态度。mindset:一套人们应该持有的确定的态度&…

discuz安装_手动搭建 Discuz! 论坛

一、搭建LAMP环境安装软件(Apache、MariaDB、PHP)yum install httpd php php-fpm php-mysql mariadb mariadb-server -y2.启动服务systemctl start httpdsystemctl start mariadbsystemctl start php-fpm3.安装后首次启动mariadb设置mysql_secure_installation4.登录 MariaDB&a…

蓝桥杯 1223 第 2 场 小白入门赛

蓝桥小课堂-平方和 模拟 1 2 2 2 3 2 ⋯ n 2 n ⋅ ( n 1 ) ⋅ ( 2 n 1 ) 6 1^22^23^2\cdotsn^2\dfrac{n\;\cdot\;(n 1)\;\cdot\;(2n1)}{6} 122232⋯n26n⋅(n1)⋅(2n1)​。 write(n * (n 1) * (n * 2 1) / 6);房顶漏水啦 m a x ( 最大的行 − 最小的行 , 最大的列 −…

jar包是什么意思_面试难度五颗星:JVM有Full GC,为什么还会 OutOfMemoryError?

点击上方蓝色“后端面试那些事儿”,选择“设为星标”学最好的别人,做最好的我们来源:R 大zhihu.com/question/38511221问题:R大回复平时有逛知乎的习惯,一般对JVM相关话题比较感兴趣。偶然看到这个问题,结果…

系统执行sql很慢达梦工具执行很快的简单解决方式

现象描述:系统功能查询很慢,拷贝查询sql到达梦工具中执行速度很快 1.问题分析: 达梦SQL执行耗时异常问题排查_qq_39693441的博客-CSDN博客_sql耗时分析 2.解决方式1: 在程序sql中拼接随机数如: select /*动态随机数*…

roads 构筑极致用户体验_长安马自达「悦马星空」计划上线,为用户带来极致服务体验...

日前,第十八届广州车展顺利举行。期间各大汽车品牌齐聚亮相,这其中,也包括众人熟悉的长安马自达。据悉,在本次车展上,长安马自达除携品牌全系车型次世代MAZDA3 昂克赛拉、2020款MAZDA CX-5、MAZDA CX-30和MAZDA CX-8亮相外,还正式发布「悦马星空」用户共创计划。资料显示,「悦马…

从数百万个光纤(而不是数千个线程)中查询数据库

jOOQ是在Java中执行SQL的好方法, Quasar光纤带来了大大提高的并发性 我们很高兴在平行宇宙的 Fabio Tudone的jOOQ博客上宣布另一个非常有趣的来宾帖子。 Parallel Universe开发了一个开源堆栈,使开发人员可以轻松地在JVM上对极端的并发应用程序进行编码…

Oracle11.2.0.4 RAC安装文档

1 环境配置 参考官方文档《Grid Infrastructure Installation Guide for Linux》 1.1 软件环境 操作系统: [roothowe1 ~]# cat /etc/redhat-release Red Hat Enterprise Linux Server release 6.2 (Santiago) [roothowe1 ~]# uname -a Linux howe1 2.6.32-220.el6.i…

captcha库_将CAPTCHA添加到您的GWT应用程序

captcha库什么是验证码? 在一个充满恶意机器人的世界中,您应该怎么做才能保护您宝贵的Web应用程序? 您真正应该做的基本事情之一就是向其中添加CAPTCHA功能。 如果您不熟悉(听起来有些奇怪),则CAPTCHA是确保…

ContentProvider与ContentResolver使用

例如以下内容为从网络转载:使用ContentProvider共享数据:当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就能够向其它应用共享其数据。虽然使用其它方法也能够对外共享数据,但数据訪问方式会因…

cshtml中引用css_ASP.NET CoreMVC 中的控制器

Controller in ASP.NET Core MVC在本节中,我们将讨论 Controller 是什么以及它在 ASP.NET Core MVC 中的作用。Fiddler需要大家提前装一个工具,https://www.telerik.com/fiddlerFiddler 是一个 http 协议调试代理工具,它能够记录并检查所有你…