OC消息发送和转发机制原理

Objective-C(OC)是一门面向对象的编程语言,它在消息传递和方法调用方面具有独特的机制 。在OC中,对象通过消息来调用方法 , 而不是像传统的编程语言那样直接调用函数 。本文将深入探讨OC的消息发送和转发机制原理 , 包括其基本概念、实现过程、代码示例以及实际应用场景 。

OC消息发送和转发机制原理

文章插图
第一步:什么是消息发送和转发机制?在Objective-C中,对象之间的通信是通过消息传递来实现的 。当一个对象想要调用另一个对象的方法时,它会发送一个消息,然后由接收消息的对象来响应这个消息 。这种方式与传统的函数调用不同 , 使得OC具有更高的动态性和灵活性 。
【OC消息发送和转发机制原理】消息发送和转发机制分为三个阶段:
  • 消息发送(Message Sending): 当一个对象收到一个消息时 , 它首先会在自己的方法列表中查找是否有与消息对应的方法 。如果找到了,就会执行该方法;如果找不到,就会进入下一阶段 。
  • 消息转发(Message Forwarding): 如果对象无法找到与消息对应的方法,它将进入消息转发过程 。在这个阶段,对象有机会将消息转发给其他对象 。
  • 未知消息处理(Handling Unknown Messages): 如果经过消息转发仍未找到合适的方法,系统将调用-doesNotRecognizeSelector:方法,该方法默认会引发异常 , 但也可以由开发者进行重写以执行其他操作 。
第二步:消息发送的原理消息发送是OC的核心机制之一,它使得方法的调用更为动态和灵活 。消息发送的原理可以概括为以下几个步骤:
  • 创建消息: 当一个对象想要调用方法时,它会创建一个消息 , 包括消息的接收者、方法名(选择器)以及方法的参数 。
  • 查找方法: 对象会在自己的方法列表(方法分发表)中查找是否存在与消息对应的方法 。方法分发表是一个映射,将选择器与方法的实现关联起来 。
  • 调用方法: 如果找到了与消息对应的方法,对象将直接调用该方法并执行 。如果找不到,消息将进入消息转发阶段 。
第三步:消息转发的原理当一个对象无法找到与消息对应的方法时,它会进入消息转发过程 。消息转发的原理可以概括为以下几个步骤:
  • 消息转发的开始: 对象收到无法处理的消息后,会调用-forwardingTargetForSelector:方法,该方法允许对象将消息转发给其他对象 。如果返回一个有效的对象,则消息将被转发给该对象 。
  • 备用接收者: 如果-forwardingTargetForSelector:方法返回nil,对象会继续查找是否存在备用接收者(Alternate Receiver),这通常是另一个对象 。备用接收者可以通过覆盖+ (id)forwardingTargetForSelector:(SEL)aSelector类方法来指定 。
  • 动态方法解析: 如果没有备用接收者或备用接收者也无法处理消息,对象将调用+resolveInstanceMethod:或+resolveClassMethod:方法来动态添加方法 。这允许开发者在运行时为对象添加新方法 。
  • 完整的消息转发: 如果前面的步骤都失败 , 对象将调用-forwardInvocation:方法,将消息以NSInvocation对象的形式传递给该方法 。在-forwardInvocation:方法中,开发者可以手动处理消息的转发,包括将消息发送给其他对象或执行其他操作 。
第四步:消息发送和转发的代码示例让我们通过一个简单的代码示例来演示消息发送和转发的过程:
#import <Foundation/Foundation.h>@interface MyObject : NSObject- (void)methodA;@end@implementation MyObject- (void)methodA {NSLog(@"Method A is called");}@endint mAIn(int argc, const char * argv[]) {@autoreleasepool {MyObject *obj = [[MyObject alloc] init];// 调用已存在的方法[obj methodA]; // 输出 "Method A is called"// 调用不存在的方法[obj methodB]; // 触发消息转发// 使用动态方法解析添加方法class_addMethod([MyObject class], @selector(methodB), class_getMethodImplementation([MyObject class], @selector(methodA)), "v@:");// 再次调用方法[obj methodB]; // 输出 "Method A is called"}return 0;}在这个示例中,我们首先创建了一个MyObject类 , 其中包含了methodA方法 。然后,我们创建了一个对象obj , 并尝试调用methodA方法,这是一个已存在的方法 。


推荐阅读