iOS消息转发方法签名forselector



所以我正在寻找消息转发和运行一些单元测试时,我遇到了一些稀缺的资源,包括苹果自己的品牌的文档使用forwardInvocation:,据我所知需要methodSignatureForSelector:工作。

现在我得到了methodSignatureForSelector:的一般想法,需要看看你试图转发消息的对象是否有匹配的方法名称和参数,所以它可以调用forwardInvocation:我的问题是为什么在苹果的文档中它说要调用超类的methodSignatureForSelector:的实现像这样…

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

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

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

TL;博士为什么我需要[super methodSignatureForSelector:selector]; ?

您是正确的—示例尝试从超类获取方法签名,如果无法获取,则向代理请求一个。在整个转发和继承部分,Apple正在指导您如何使用消息转发-您是否选择收听取决于您:)

为了完整地解释,我将浏览文档的主要部分:

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

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

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

  • 关键词是"可能",所以苹果会给你推荐。苹果公司表示,如果你想让myWarrior对象在我上面的例子中返回YES,因为你把negotiate转发给了代理对象,那么你需要覆盖respondsToSelector方法。现在请注意,除了negotiate之外,您还可以调用其他方法,可能在代理中不希望返回YES。例如,外交家类可能有一个havePeaceCelebration方法。当战士职业收到此消息时,您可能没有实现将消息转发给外交家职业(因为战士没有和平庆祝活动),因此您将希望返回NO

    此外,父类可能具有不在Warrior类中的chooseWeapon方法。如果你调用[myWarrior respondsToSelector:chooseWeapon],你肯定想检查超类是否响应它,因为代理(作为外交家)没有。

    最后,父类和代理类都可能响应选择器。Apple似乎建议父类应该胜出——一个Warrior首先是一个Warrior,对于某些方法是一个Diplomat,只有当你强迫它是。你最终如何实现它取决于你。

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

  • 关键字是should——同样是推荐。这是您提供的代码之前的语句。这是与respondsToSelector相同的推理,并且说对象应该是一个好公民。战士职业有可能处理一些远程消息,但不能处理其他消息,外交家职业也是如此。如果您选择总是将其转发给代理,那么如果转发的消息是Warrior的超类可以处理的,则可能会令人困惑。或者更糟的是,它可能会转发Warrior的超类可以处理而代理不能处理的消息——这可能会导致异常。

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

    最新更新