1

因此,当我遇到一些资源匮乏的情况时,我正在研究消息转发forwardInvocation:并运行一些单元测试,包括苹果自己品牌的使用文档,据我所知需要methodSignatureForSelector:工作。

methodSignatureForSelector:现在我得到了查看您尝试将消息转发到的对象是否具有匹配的方法名称和参数所需的一般概念,因此它可以调用forwardInvocation:我的问题是为什么在苹果文档中它说调用超类的methodSignatureForSelector:实现所以...

- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
    NSMethodSignature* signature = [super methodSignatureForSelector:selector];
    if (!signature) {
        signature = [surrogate methodSignatureForSelector:selector];
    }
    return signature;
}

对我来说,这看起来像是在说“如果我继承的所有类都没有处理这个方法的方法,请检查代理对象是否有。”

在谈判方法方面,苹果给出的例子是勇士代替外交官行事。鉴于这个例子,我不明白你为什么要检查战士或其任何父母是否有适当的方法签名来转发。所以这让我相信它的存在是出于另一个原因,一个我想不出的原因,有人可以给我一个例子或帮助澄清我可能遗漏的地方吗?

TL;DR 为什么我需要[super methodSignatureForSelector:selector];

4

2 回答 2

5

你是对的——这个例子试图从超类中获取方法签名,如果不能,它会向代理请求一个。在整个转发和继承部分,Apple 正在指导您如何使用消息转发 - 您是否选择收听取决于您 :)

为了充分解释,我将介绍文档的主要部分:

  1. 尽管转发模拟了继承,但 NSObject 类从不混淆两者。像 respondsToSelector: 和 isKindOfClass: 这样的方法只查看继承层次结构,从不查看转发链。

实现消息转发不会立即影响respondsToSelectorisKindOfClass方法。如果您转发negotiate给代理,如果您调用[myWarrior respondsToSelector:negotiate]将返回NO,如果该方法在继承层次结构中不存在。

  1. 如果您使用转发来设置代理对象或扩展类的功能,那么转发机制应该继承一样透明。如果您希望您的对象表现得好像它们真正继承了它们将消息转发到的对象的行为,您将需要重新实现 respondsToSelector: 和 isKindOfClass: 方法以包含您的转发算法。

关键字可能是 - 所以苹果给你一个建议。Apple 声明如果您希望 myWarrior 对象YES在我上面的示例中返回,因为您转发negotiate到代理对象,那么您需要覆盖该respondsToSelector方法。现在请注意,除了您可以调用之外还有其他方法negotiate,可能在您不希望返回的代理中YES。例如,Diplomat 类可能有一个havePeaceCelebration方法。当 Warrior 类收到此消息时,您可能尚未将消息转发给 Diplomat 类(因为 Warriors 没有和平庆祝活动),因此您将想要返回NO

此外,父类可能有一个chooseWeaponWarrior 类中没有的方法。如果你打电话给[myWarrior respondsToSelector:chooseWeapon]你,你肯定想检查超类是否响应它,因为代理人(作为外交官)没有。

最后,父类和代理都可能响应选择器。苹果似乎建议父类应该胜出——战士首先是战士,对于某些方法来说是外交官,除非你强迫它这样做。你最终如何实现它取决于你。

  1. 除了 respondsToSelector: 和 isKindOfClass:,instancesRespondToSelector: 方法也应该反映转发算法。如果使用协议,conformsToProtocol: 方法同样应该添加到列表中。类似地,如果一个对象转发它接收到的任何远程消息,它应该有一个版本的 methodSignatureForSelector: 可以返回最终响应转发消息的方法的准确描述;例如,如果一个对象能够将消息转发给它的代理,你将实现 methodSignatureForSelector: 如下:

关键字是应该 - 再次推荐。这是您提供的代码之前的声明。这与 的推理相同respondsToSelector,并且说对象应该是一个好公民。Warrior 类可以处理一些远程消息,但不能处理其他消息,Diplomat 类也是如此。如果您选择始终将其转发给代理,如果转发的消息是 Warrior 的超类可以处理的,则可能会造成混淆。或者更糟糕的是,它可能会转发 Warrior 的超类可以处理但代理不能处理的消息 - 可能会导致异常。

于 2015-07-27T07:53:38.983 回答
1

如果您向不处理该消息的对象发送消息,则在宣布错误之前,运行时会向对象发送 forwardInvocation: 消息,其中 NSInvocation 对象作为其唯一参数 - NSInvocation 对象封装了原始消息和传递的参数用它。

于 2016-05-12T18:58:32.717 回答