我只是开始玩Objective C(编写玩具iPhone应用程序),我对用于发送消息的底层机制很好奇.我对C++中的虚函数一般如何实现以及相对于静态或非虚方法调用的成本有着很好的理解,但是我没有任何Obj-C的背景来知道消息是如何发送的.浏览一下,我发现了this个松散的基准测试,其中提到IMP缓存的消息比虚拟函数调用快,而虚拟函数调用又比标准消息发送快.

我并没有试图优化任何东西,只是更深入地了解消息是如何被发送的.

  • Obj-C消息是如何发送的?
  • 实例方法指针是如何被缓存的?您(通常)能通过阅读代码判断消息是否会被缓存吗?
  • 类方法与C++函数(或C++中的静态类方法)本质上相同,或者它们有更多的东西吗?

我知道其中一些问题可能是"依赖于实现",但只有一个实现真正重要.

推荐答案

How are Obj-C messages dispatched?

Objective-C消息使用运行时的objc_msgSend()函数进行调度.如图Apple docs所示,该函数至少有两个参数:

  1. 接收对象
  2. 消息的 Select 器
  3. [发送的消息的变量列表.]

类的实例有一个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指针指向它的元类对象,而元类对象又有超级元类对象,它可以从中继承类对象.对类方法的方法分派如下:

  1. 分派系统遵循类对象指向元类对象的isa指针
  2. 在元类对象的方法表中搜索类方法.
  3. 如果没有找到,搜索将继续到元类对象的超类,搜索将继续.
  4. 这个过程会重复,直到找到该方法,或者直到它到达根元类,并引发异常.

Objective-c相关问答推荐

iphone - 防止uiscrollview通过滚动

如何用零填充左侧的整数?

使用 AVAudioplayer 在后台播放音乐

如何将变量参数传递给另一个方法?

在 Objective C 中动态调用类方法

animateWithDuration:animations: 会阻塞主线程吗?

改变 RGB colored颜色 的色调

Objective C 代码是否有 github markdown 语言标识符?

在 viewDidAppear 之前无法正确设置框架

setFont 已弃用?

如何判断特定的 ViewController 视图当前是否可见?

UILabel 的角半径属性在 iOS 7.1 中不起作用

dispatch_async(dispatch_get_main_queue(), ^{...});等到完成?

如何在 Cocoa 中获取 NSArray 的第一个 x 元素?

可以在 NSLocalizedString 中使用变量和/或参数吗?

UICollectionView 断言失败

在 iPhone 上查找用户的 Documents 目录的最佳方法是什么?

如何在 iOS 中创建自定义 UIActivity?

Xcode 如何加载主情节提要?

找出窗口中的 UIBarButtonItem 框架?