objective-c中的消息转发

 

        将消息发送给没有实现该消息方法的对象时,通常会出现运行时错误。这时,我们可以将不能被处理的消息转送给其他对象,让其他对象来处理该消息。

首先,将某消息发送到相应的接受者。如果接收者没有实现对应消息的相应方法,运行时系统会发送如下消息给接收者。

- (void)forwardInvocation: (NSInvocation *)anInvocation

这个方法在NSObject中定义,所有的对象都可以处理。

默认情况下,如果不能处理接收到的消息,在forwardInvocation:中将调用如下方法。

- (void)doesNotRecognizeSelector: (SEL) aSelector

生成错误消息,表示异常NSInvalidArgumentException发生,无法处理参数选择器对应的消息。

也就是说,只要接收者重定义了forwardInvocation:方法,当被发送不能处理的消息时,就可以将其转送给其他对象处理,或者自己执行错误处理。

forwardInvocation:的参数是一个NSInvocation对象,该对象中保存了目标,选择器,参数等消息发送所必需的全部元素。

NSInvocation中的主要方法如下:

- (SEL) selector

    返回设定的选择器。

- (id) target

     返回设定的目标。

- (void)invokeWithTarget: (id) anObject

    向目标参数对象发送表示接收者的消息,将消息的结果返回给源发送者。

注意:只有参数个数固定的消息才可以转发,参数列表不确定的消息不能实现转发。

 

为了使运行时系统能够使用转送对象信息生成NSInvocation实例,必须重新定义返回的方法签名对象。其中类NSMethodSignature的对象可以保存方法的参数和返回值,但在消息转送或通信之外的情况下,程序中并不处理该方法。可以使用定义在NSObject中的如下方法来返回方法签名。

-(NSMethodSignature *) methodSignatureForSeletor: (SEL) aSelector

使用转送方法处理的消息不能被respondsToSelector:等方法检测到,如需用respondsToSelector:进行检查时,需要对该方法进行重定义。

如果有需要,也可以利用doesNotRecognizeSelector:来禁止使用某个方法。

例如,想禁止使用setName:方法时,可以进行如下处理:

- (void)setName:(NSStirng *)name

{

     [self doesNotRecognizeSelector:_cmd];

}

其中_cmd代表方法本身,也可以用@selector(setName:)来代替。


下面举一个具体的例子:

首先,需要创建两个类,一个主类,另一个处理主类不能处理的消息。

主类中有一个属性如下:


该属性用于保存当收到不能处理的消息时,代为处理消息的对象。

在主类中实消息转发现所需的两个方法:

objective-c中的消息转发_第1张图片

在处理类中实现替代主类处理消息的方法体:


在程序中如下调用:


其中,Son是主类,该类中并未定义handleMethod方法。Another是处理类,其中实现了handleMethod方法。运行结果如下:


倘若向son发送其中已实现相应方法的消息,例如sonInstanceMethod,则其运行结果如下:


由上可见,只有当被发送消息的对象响应不了相关消息时,方法forwardInvocation:和methodSignatureForSeletor:方法才会被调用。而且的确可以将不能处理的方法交给另一个可以响应该方法的对象来处理。

你可能感兴趣的:(objective-c中的消息转发)