iOS 消息转发方法SignatureForSelector

iOS Message Forwarding methodSignatureForSelector

所以我正在寻找 into message forwarding 和 运行 一些单元测试,当我遇到一些稀缺资源时,包括苹果自己品牌的使用 forwardInvocation: 的文档,尽我所能tell 需要 methodSignatureForSelector: 才能工作。

现在我得到了一般的想法,需要 methodSignatureForSelector: 来查看您尝试将消息转发到的 object 是否具有匹配的方法名称和参数,以便它可以调用 forwardInvocation: 我的问题是为什么在苹果文档中它说要像这样调用超类的 methodSignatureForSelector: 实现...

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

对我来说,这看起来像是在说“如果我继承自的 类 的 none 有处理此方法的方法,请检查代理项 object 是否有。 “

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

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

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

为了全面解释,我将浏览文档的主要部分:

  1. Although forwarding mimics inheritance, the NSObject class never confuses the two. Methods like respondsToSelector: and isKindOfClass: look only at the inheritance hierarchy, never at the forwarding chain.

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

  1. If you use forwarding to set up a surrogate object or to extend the capabilities of a class, the forwarding mechanism should probably be as transparent as inheritance. If you want your objects to act as if they truly inherited the behavior of the objects they forward messages to, you’ll need to re-implement the respondsToSelector: and isKindOfClass: methods to include your forwarding algorithm.

关键字可能是 - 所以 Apple 正在给您推荐。 Apple 声明如果你希望 myWarrior 对象在我上面的例子中 return YES 因为你将 negotiate 转发给代理对象,那么你需要覆盖 respondsToSelector 方法.现在请注意,尽管除了 negotiate 之外还有其他方法可以调用,但可能在您不希望 return YES 的代理项中调用。例如,Diplomat class 可能有一个 havePeaceCelebration 方法。当 Warrior class 收到此消息时,您可能没有实现将消息转发给 Diplomat class(因为 Warriors 没有和平庆祝活动)因此您需要 return NO

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

最后,父 class 和代理都可以响应选择器。 Apple 似乎建议父 class 应该胜出 - Warrior 首先是 Warrior,某些方法是 Diplomat,前提是你强迫它成为。你最终如何实施它取决于你。

  1. In addition to respondsToSelector: and isKindOfClass:, the instancesRespondToSelector: method should also mirror the forwarding algorithm. If protocols are used, the conformsToProtocol: method should likewise be added to the list. Similarly, if an object forwards any remote messages it receives, it should have a version of methodSignatureForSelector: that can return accurate descriptions of the methods that ultimately respond to the forwarded messages; for example, if an object is able to forward a message to its surrogate, you would implement methodSignatureForSelector: as follows:

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

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