iOS RunTime之三:消息发送

作者: s_在路上 | 来源:发表于2016-09-20 11:59 被阅读184次

    由上面一章中,我们了解了什么是RunTime的数据结构,下面了解一下Runtime的消息发送。

    我们知道[object doSomething]被编译器转化为:

    id objc_msgSend ( id self, SEL op, ... );
    

    Objective-C中,消息直到运行时才会绑定到方法的实现上。编译器会把代码中[object doSomething]转换成objc_msgSend消息函数,这个函数完成了动态绑定的所有事情,它的运行流程如下:

    • 检查selector是否需要忽略。
    • 检查target是否为nil。如果为nil,直接cleanup,然后return。(这就是我们可以向nil发送消息的原因。)
    • 然后在targetClass中根据Selector去找IMP

    寻找IMP的过程:

    • 先从当前classcache方法列表(cache methodLists)里去找。
    • 如果找到了,跳到对应函数实现。
    • 如果没找到,就从class的方法列表(methodLists)里找。
    • 如果还找不到,就到super class的方法列表里找,直到找到基类(NSObject)为止。
    • 最后再找不到,就会进入动态方法解析和消息转发的机制。
    Paste_Image.png

    注意:

    • 这里说的分发表其实就是Class中的方法列表,它将方法选择器和方法实现地质联系起来。
    • 消息的发送其实就是先确定object接受者对象,然后根据isa指针查找其方法然后跳转过去并执行。
    • 但是编译期间,是无法确定object接受者对象。只有在程序运行期间,object接受者对象才能得到确定。这种在运行期间才确定object接受者对象,Objective-C称为动态绑定。
    • 消息发送这种工作机制明显区别另一著名面向对象编程语言——C++或者JavaC++或者Java调用对象的函数,函数与对象之间的关系,在编译期间就必须严格确定。比如Car这个对象里面没有定义函数名为fly的函数,编译器不会通过,而是会报错。Objective-C如果向Car这个对象发送字符串为flyselector,即使car没有实现fly方法,编译器依然能够通过,但是运行期间则会因为获取不到实际执行的方法而抛出异常。
    • 消息发送的设计使得编译期间Objective-C非常包容对象所属的类。在Objective-C语言中你可以向任何包括空指针nil在内的对象发你想发的消息。
    • 消息发送的机制使得在不重新编译的情况下,在运行期间,干预或者说hook原来的target(方法、变量等)变得更易于实现,更有实际应用价值,这个是需要依赖于消息发送和动态绑定的实现机制——Runtime

    相关文章

      网友评论

        本文标题:iOS RunTime之三:消息发送

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