返回

OC消息机制(二)lookUpImp慢速查找

IOS

前言

在之前的文章《OC消息机制(一)objc_msgSend_uncached分析》中,我们深入探讨了消息发送的底层实现,了解到objc_msgSend_uncached函数在消息接收者不是已知类时,会执行慢速查找。在本文中,我们将继续深入挖掘慢速查找的奥秘,分析lookUpImp函数的工作原理,看看它是如何为未知类的消息接收者找到正确的实现方法的。

lookUpImp函数剖析

lookUpImp函数是慢速查找的核心,它负责查找消息接收者类的实现方法。其函数原型如下:

IMP lookUpImp(Class cls, SEL sel)

其中,cls是消息接收者的类,sel是消息选择器。

lookUpImp函数的执行流程主要分为以下几步:

  1. 查找父类实现方法 :首先,lookUpImp函数会查找cls类的父类实现方法。如果找到,直接返回该实现方法。

  2. 遍历协议列表 :如果在父类中没有找到实现方法,lookUpImp函数会遍历cls类所遵循的协议列表,依次查找实现方法。如果找到,直接返回该实现方法。

  3. 调用objc_msgForward :如果在父类和协议中都未找到实现方法,lookUpImp函数会调用objc_msgForward函数,将消息转发给接收者的superclass。

IMP forward_imp = cls->isa->forward_imp;
if (forward_imp)
    return forward_imp(cls, sel);
  1. 使用dispatch_once :如果在superclass中也未找到实现方法,lookUpImp函数会使用dispatch_once函数创建一个单例对象,该对象包含一个方法映射表,其中记录了类名、选择器和实现方法之间的对应关系。
dispatch_once(&objc_lookUpImpCacheOnce, ^{
    cache = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
                                     &kCFTypeDictionaryKeyCallBacks,
                                     &objc_lookUpImpCacheValueCallBacks);
});
  1. 查找缓存 :在方法映射表中查找cls类和sel选择器对应的实现方法。如果找到,直接返回该实现方法。

  2. 查找Category实现方法 :如果在方法映射表中未找到实现方法,lookUpImp函数会遍历cls类所关联的Category列表,依次查找实现方法。如果找到,直接返回该实现方法。

  3. 返回nil :如果在所有可能的位置都未找到实现方法,lookUpImp函数会返回nil。

实例分析

让我们以一个具体的例子来分析lookUpImp函数的执行过程。假设我们有一个名为Person的类,该类有一个名为setName:的方法。现在我们创建一个Student类,它继承自Person类,并覆盖了setName:方法。

@interface Person : NSObject
- (void)setName:(NSString *)name;
@end

@interface Student : Person
- (void)setName:(NSString *)name;
@end

现在,我们发送一条setName:消息给一个Student对象。消息发送流程如下:

  1. objc_msgSend 函数调用objc_msgSend_uncached 函数,因为Student类不是已知类。

  2. objc_msgSend_uncached 函数发现Student类不是已知类,于是进入慢速查找。

  3. lookUpImp 函数首先查找Student类的父类Person的实现方法,发现有setName:方法,于是直接返回该实现方法。

  4. 消息最终调用了Person类的setName:方法。

性能优化

慢速查找是一个相对耗时的操作,尤其是当需要遍历大量的协议和Category时。为了优化性能,我们可以采取以下措施:

  • 使用已知类 :尽量使用已知类,避免触发慢速查找。
  • 减少协议和Category的使用 :过多的协议和Category会增加慢速查找的开销。
  • 使用消息转发 :通过实现- (id)forwardingTargetForSelector:(SEL)aSelector方法,可以将消息转发给其他对象,避免慢速查找。

总结

慢速查找是OC消息机制中的一种重要机制,它确保了消息可以发送给未知类的消息接收者。lookUpImp函数是慢速查找的核心,它通过遍历父类、协议和Category等位置来查找实现方法。了解慢速查找的原理有助于我们优化OC程序的性能。

关键词: