美文网首页
第11条:理解objc_msgSend的作用

第11条:理解objc_msgSend的作用

作者: MrSYLong | 来源:发表于2018-08-12 17:37 被阅读11次

    在对象上调用方法,就叫做“传递消息”。消息有“名称”或“选择器”(方法的名字),可以接受参数,可能有返回值。

    C语言的函数调用,使用“静态绑定”,在编译期就能决定所应调用的函数。

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

    给对象发送消息,一般这样写:

    id returnValue = [someObject messageName:parameter];
    
    说明:
    someObject:接受者
    messageName:选择器
    选择器与参数合起来成为“消息”
    

    编译器看到这条消息后,将其转化为一条标准的C语言函数调用

    // 消息传递机制的核心函数
    void objc_msgSend(id self, SEL cmd, ...)
    
    说明:
    是一个“参数可变的函数”,能接受两个或两个以上的参数。
    第一个参数:接受者
    第二个参数:选择器(SEL是选择器的类型)
    后续参数就是消息中的参数,顺序不变。
    选择器指的就是方法的名字。
    

    编译器将例子中的消息转换为:

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

    消息调用的过程:

    objc_msgSend函数会依据接受者(类、对象)与选择器的类型(对象方法,类方法)调用适当的方法。

    上面的方法需要在接受者(对象)所属的类中搜寻其“方法列表”,如果能找到与选择器名称相符的方法,就跳至其实现代码。若是找不到,那就沿着继承体系继续向上查找,等找到合适的方法在跳转。如果最终找不到相符的方法,那就执行“消息转发”。

    在这个过程中,objc_msgSend会将匹配结果缓存在“快速映射表”里面,每个类都有这样一块缓存,若是稍后还向该类发送与选择器相同的消息,那执行起来就快了。

    其他“边界”情况,则需要交由OC运行环境的其他函数处理:

    objc_msgSend_stret:待发送消息要返回结构体,且返回值大小CPU的结存器能够容纳,用此函数处理消息,若无法容纳,由另一个函数执行,通过分配在栈上的某个变量来处理消息所返回的结构体。

    objc_msgSend_fpret:消息返回浮点数。

    objc_msgSendSuper:要给超类发送消息。还有与上面两个函数等效的用于处理发给super消息的函数。

    objc_msgSend等函数一旦找到应该调用的方法实现之后,就会“跳转过去”,是因为OC对象的每个方法都可以视为简单的C函数,其原型如下:

    <return_type> Class_selector(id self, SEL _cmd, ...)
    

    每个类里都有一张表格,其中的指针都会指向这种函数,而选择器的名称则是查表时所用的“键”,objc_msgSend等函数正是通过这张表格来寻找应该执行的方法并跳至其实现的。

    相关文章

      网友评论

          本文标题:第11条:理解objc_msgSend的作用

          本文链接:https://www.haomeiwen.com/subject/qqasbftx.html