返回

探索Runtime底层原理(一):方法查找的奥秘

IOS

Runtime,作为iOS开发中的重要基石,其底层原理一直是广大开发者探索的奥秘。在本次旅程中,我们将深入探究Runtime中的方法查找机制,揭开其背后的运作原理。

Runtime简介

Runtime是Objective-C运行时的核心部分,它负责动态语言特性的实现,包括动态类型检查、动态消息发送和方法查找等。Runtime本质上是一个大型的C函数库,提供了一系列强大的API,允许开发者在运行时操作Objective-C对象、类和方法。

方法查找

方法查找是Runtime最核心的功能之一。当一个对象收到消息时,Runtime负责查找该消息对应的实现方法。这个过程看似简单,但其实涉及到一系列复杂的操作。

CacheLookup宏

Runtime使用了一个名为CacheLookup的宏来加速方法查找。CacheLookup宏通过查找一个预先计算的查找表,快速确定方法实现的地址。这个查找表存储在每个类的元类中,包含了该类所有方法的地址。

#define CacheLookup(cls, sel)   *(*(typeof(CacheLookup(cls, sel))) * *objc_msgLookup((Class)cls, sel))

查找过程

如果CacheLookup失败,Runtime将使用更全面的方法查找过程:

  1. 查找类方法列表: Runtime从目标类的类方法列表中开始查找。如果找到匹配的方法,则返回该方法地址。
  2. 查找父类方法列表: 如果在类方法列表中找不到方法,Runtime将继续在父类的方法列表中查找。这个过程递归进行,直到达到根类NSObject。
  3. 查找协议方法列表: 如果在父类中找不到方法,Runtime将检查目标类是否遵循任何协议。如果找到匹配的协议方法,则返回该方法地址。
  4. 查找分类方法列表: 如果在协议中找不到方法,Runtime将继续在目标类的分类方法列表中查找。如果找到匹配的方法,则返回该方法地址。
  5. 方法未找到: 如果在所有这些步骤中都找不到方法,则Runtime会抛出NSInvalidArgumentException异常。

实例

为了更好地理解方法查找过程,让我们考虑以下示例:

@interface Person : NSObject
- (void)sayHello;
@end

@implementation Person
- (void)sayHello {
    NSLog(@"Hello world!");
}
@end

当我们向Person对象发送sayHello消息时,Runtime会按照以下步骤查找方法实现:

  1. 在Person类的类方法列表中查找sayHello方法。
  2. 由于Person类没有父类,所以不会进行父类查找。
  3. Person类也没有遵循任何协议。
  4. Person类也没有任何分类。
  5. 由于在任何步骤中都没有找到方法,Runtime会抛出NSInvalidArgumentException异常。

总结

方法查找是Runtime的重要组成部分,它负责动态地查找消息对应的实现方法。Runtime使用CacheLookup宏和全面的查找过程来提高效率和准确性。通过了解方法查找的原理,我们可以更好地理解Runtime的工作原理,并编写出更健壮的代码。