Runtime之objc_msgSend函数

来源:互联网 发布:c4d软件安装教程 编辑:程序博客网 时间:2024/05/29 15:20

首先了解一下什么是Runtime?

Runtime顾名思义即为运行时。就是系统运行时候的一些机制,它提供了一些使得对象之间能够传递消息的重要函数,其中最主要的就是消息机制了。相较于C语言而言,C语言使用的是“静态绑定”,函数的调用在编译期就能知道运行期所需要调用的函数了,编译完成之后就按照顺序执行(面向过程就是这么任性)。而OC使用的是“动态绑定”特性,也就是说编译器在编译期的时候无法决定运行期调用哪个函数,也就是说在编译阶段,OC可以调用任何函数,即使该函数未实现,但只要声明过就不会报错,而C语言则会报错,对象在接收到消息之后,究竟该调用哪个方法完全由运行期决定,甚至可以在程序运行时改变.

1:在对象上调用方法是OC 中经常使用的功能,用 OC 的术语来说,叫做传递消息.消息有名称和选择子,可以接受参数,而且可能有返回值.

2:在 OC 中,如果向某个对象发送消息,那么就会使用动态绑定机制来决定需要调用的方法,在底层所有方法都是c语言函数,然后对象在接收到消息之后,究竟该调用哪个方法则完全于运行期决定,甚至可以在运行时改变,这些特性也使得oc成为了一门真正动态的语言.

3:给对象发送消息可以这样写:

id returnValue = [someObject messageName:parameter];

这个例子中, someObject叫做接受者,messageName叫做选择子,选择子与参数合起来叫做消息.编译器看到此消息之后,将其转换为一条标准的c语言函数,叫做objc_msgSend,其原型为id objc_msgSend(id self, SEL op, …)这是一个参数个数可变的函数,能够接收两个或者两个以上的参数.

第一个参数代表接受者,objc_msgSend第一个参数类型id,它是一个指向类实例的指针.typedef struct objc_object *id;

objc_object原型为:
struct objc_object { Class isa ; };
objc_object结构体包含一个isa指针,根据isa指针就可以找到对象所属的类.

第二个参数代表选择子(SEL是选择子的类型),它是selector在Objc中的表示类型(Swift中是Selector类)。selector是方法选择器,可以理解为区分方法的 ID,而这个 ID 的数据结构是SEL:

typedef struct objc_selector *SEL;
其实它就是个映射到方法的C字符串,你可以用 Objc 编译器命令@selector()或者 Runtime 系统的sel_registerName函数来获得一个SEL类型的方法选择器。

后续参数就是消息中的那些参数,其顺序不变,选择子指的就是方法的名称.

编译器会把刚才那个例子中的消息装换成为如下的函数 :

id returnValue = objc_msgSend(someObject,@selector(messageName:),parameter);

objc_msgSend函数会依据接受者与选择子的类型来调用适当的方法.为了完成此操作,该方法需要在接受者所属的类中搜索其”方法列表”,如果能够找到与选择子名称相符合的方法,就跳转至其实现代码.若是找不到,那就沿着继承体系继续向上査找,等找到了合适的方法之后再调整.如果最终还是找不到相符合的方法,那么就执行”消息转发”.说来,想调用一个方法似乎需要很多步骤.但是幸运的是,objc_msgSend会将匹配的结果缓存到”快速映射表”里面,每个类都有这样一块缓存,若是后面还向该类发送与选择子相同的消息,那么执行起来就很快了.实际一点的例子:

当你写下面这样的代码时
[tableView cellForRowAtIndexPath:indexPath];

编译器实际上把它转换成下面这样的C函数调用
objc_msgSend(tableView, @selector(cellForRowAtIndexPath:), indexPath);

5:下面理解一下其他几个函数:

objc_msgSend_stret():如果待发送的消息要返回结构体,那么交给此函数处理.只有当CPU的寄存器能够容纳得下消息返回类型时,这个函数才能够处理此消息.若是无法容纳于 CPU 寄存器中,那么就由另一个函数执行派发.此时,那个函数会通过分配在栈上的某个变量来处理消息所返回的结构体.

objc_msgSend_fpret():如果消息返回的是浮点数,那么可由此函数来处理,在某些架构的 CPU 中调用函数时,需要对”浮点数寄存器”做特殊处理.

objc_msgSendSuper():如果要对超类发送消息,那么就要交给此函数处理.也有与objc_msgSend_stret(),objc_msgSend_fpret()两个等效的函数用于处理超类的相应消息.

推荐播客:

http://www.cocoachina.com/ios/20150812/12992.html

0 0
原创粉丝点击