How are Obj-C messages dispatched?
Objective-C消息使用运行时的objc_msgSend()
函数进行调度.如图Apple docs所示,该函数至少有两个参数:
- 接收对象
- 消息的 Select 器
- [发送的消息的变量列表.]
类的实例有一个isa
指针,这是指向其类对象的指针.每个对象中方法的 Select 器存储在类对象中的"表"中,objc_msgSend()
函数跟随指向类对象的isa
指针,以查找该表,并判断该方法是否位于该类的表中.如果找不到,它会在类的超类的表中查找该方法.如果找不到,则继续向上移动对象树,直到找到方法或到达根对象(NSObject
).此时,将抛出一个异常.
How do Instance Method Pointers get cached and can you (in general) tell by reading the code if a message will get cached?
摘自苹果Messaging版的Objective-C运行时指南:
为了加快消息传递过程,运行时系统会在方法使用时缓存它们的 Select 器和地址.每个类都有一个单独的缓存,它可以包含继承方法以及类中定义的方法的 Select 器.在搜索分派表之前,消息传递 routine 首先判断接收对象类的缓存(理论上,曾经使用过的方法可能会再次使用).如果方法 Select 器在缓存中,则消息传递只比函数调用稍微慢一点.一旦一个程序运行足够长的时间来"预热"它的缓存,它发送的几乎所有消息都会找到一个缓存方法.缓存会动态增长,以便在程序运行时容纳新消息.
如上所述,一旦程序运行,缓存就开始发生,在程序运行足够长的时间后,大多数方法调用都将通过缓存的方法运行.正如它还说的,缓存是在使用方法时发生的,因此消息只有在使用时才会被缓存.
Are class methods essentially the same as a C function (or static class method in C++), or is there something more to them?
类对象以类似于类实例的方式处理方法分派.每个类对象都有一个对象,它在一个名为metaclass
的对象中存储自己的class个方法.类对象有自己的isa
指针指向它的元类对象,而元类对象又有超级元类对象,它可以从中继承类对象.对类方法的方法分派如下:
- 分派系统遵循类对象指向元类对象的
isa
指针
- 在元类对象的方法表中搜索类方法.
- 如果没有找到,搜索将继续到元类对象的超类,搜索将继续.
- 这个过程会重复,直到找到该方法,或者直到它到达根元类,并引发异常.