首页
学习
活动
专区
圈层
工具
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

iOS RunTime之三:消息发送

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

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

代码语言:javascript
复制
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
下一篇
举报
领券