objc-msgSend的作用

239 阅读3分钟

由于OC是C的超集,C语言使用的是“静态绑定”,也就是说编译期就能决定运行时所调用的方法。

OC调用方法叫做“传递消息”,消息有“名称”或“选择子”,可以接受参数,而且可能有返回值。

在OC中,如果想某个对象传递消息,那就会使用动态绑定机制来决定需要调用的方法。在底层所有的方法都是普通的C语言函数,然而对象收到消息后,究竟调用哪个方法则是完全决定于运行期,甚至可以在程序运行时改变。

id returnValue= [someObject messageName:parameter];

在本例中,someObject叫做“接收者”(receiver),messageName叫做“选择子”(selector)。选择子与参数合起来称为“消息”(message)。编译器看到此消息后,将其转换为一条标准的C语言函数调用,所调用的函数乃是消息传递机制中的核心函数,叫做objc_msgSend,其“原型”(prototype)如下:

void objc_msgSend(id self, SEL cmd, ...)

这是个“参数个数可变的函数”(variadic function),能接受两个或两个以上的参数。第一个参数代表接收者,第二个参数代表选择子(SEL是选择子的类型),后续参数就是消息中的那些参数,其顺序不变。选择子指的就是方法的名字。“选择子”与“方法”这两个词经常交替使用。编译器会把刚才那个例子中的消息转换为如下函数:

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

objc_msgSend函数会依据接收者与选择子的类型来调用适当的方法。为了完成此操作,该方法需要在接收者所属的类中搜寻其“方法列表”(list of methods),如果能找到与选择子名称相符的方法,就跳至其实现代码。若是找不到,那就沿着继承体系继续向上查找,等找到合适的方法之后再跳转。如果最终还是找不到相符的方法,那就执行“消息转发”(message forwarding)操作。

这么说来,想调用一个方法似乎需要很多步骤。所幸objc_msgSend会将匹配结果缓存在“快速映射表”(fast map)里面,每个类都有这样一块缓存,若是稍后还向该类发送与选择子相同的消息,那么执行起来就很快了。当然啦,这种“快速执行路径”(fast path)还是不如“静态绑定的函数调用操作”(statically bound function call)那样迅速,不过只要把选择子缓存起来了,也就不会慢很多,实际上,消息派发(message dispatch)并非应用程序的瓶颈所在。假如真是个瓶颈的话,那你可以只编写纯C函数,在调用时根据需要,把Objective-C对象的状态传进去。

特定的objc_msgSend 的一些方法

objc-msgSend_stret 待发送的消息要返回结构体

objc_msgSend_fpret 待发送的消息要返回浮点数

objc_msgSendSuper 调用父类的消息