第十一条: 理解objc_msgSend的作用

2021-11-08  本文已影响0人  iOS博仔

    在对象上调用方法是Objective-C中经常使用的功能。用Objective-C的术语来说,这叫做"传递消息"(pass a message)。消息有"名称"(name) 或 "选择子"(selector),可以接受参数,而且可能还有返回值。
    由于Objective-C的超集,所以最好先理解C语言的函数调用方式。C语言使用"静态绑定"(static binding),也就是说,在编译期就能决定运行时所应调用的函数。以下列代码为例:

#import <stdio.h>

void printHello() {
      printf("Hello, world!\n");
}

void printGoodbye() {
      printf("Goodbye, world!\n"); 
}

void doTheThing(int  type)
     void (*fnc) ();
     if (type == 0) {
          fnc = printHello; 
     }else{
          fnc = printGoodbye;
     }
    fnc();

    return 0;
}

    这时就得使用"动态绑定"(dynamic binding)了,因为所要调用的函数直到运行期才能确定。编译器在这种情况下生成的指令与刚才那个例子不同,在第一个例子中,if与else语句里都有函数调用指令。而在第二个例子中,只有一个函数调用命令,不过待调用的函数地址无法硬编码在指令之中,而是要在运行期读取出来。
    在Objective-C中,如果向某对象传递消息,那就会使用动态绑定机制来决定需要调用的方法。在底层,所有方法都是普通的C语言函数,然而对象收到消息之后,究竟该调用哪个方法则完全于运行期决定,甚至可以在程序运行时改变,这些特性使得Objective-C成为一门真正的动态语言。
    给对象发送消息可以这样来写:

id retureValue = [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)操作。消息转发将在第12条中详解。
    这么说来,想调用一个方法似乎需要很多步骤。所幸objc_msgSend会将匹配结果缓存在"快速映射表"(fast map)里面,每个类都有这样一块缓存,若是稍后还向该类发送与选择子相同的消息,那么执行起来就很快了。当然,这种"快速执行路径"(fast path)还是不如"静态绑定的函数调用操作"(statically bound function call) 那样迅速,不过只要把选择子缓存起来了,也就不会慢很多,实际上,消息派发(meeage dispatch)并非应用程序的瓶颈所在。假如真是个瓶颈的话,那你可以只编写纯C函数,在调用时根据需要,把Objective-C对象的状态传进去。
    前面讲的这部分内容只描述了部分消息的调用过程,其他"边界情况"(edge case)则需要交给Objective-C运行环境中的另一个函数来处理:

要点

上一篇下一篇

猜你喜欢

热点阅读