你怎么知道是否在Objective C中调用超类方法

时间:2011-11-23 13:51:11

标签: objective-c super respondstoselector

Class Child扩展Parent。父实现协议C,它具有可选方法,包括-(void)d。儿童实施-d;它应该调用[super d]吗?

换句话说,当且仅当某些内容会响应时,我会编写什么代码来调用[super d]?假设我不控制Parent的实现;它可能随时改变。

以下是我所想到的所有方法。我目前正在使用4号。

显然是明智的回答1:

[super d]; // Delete this line if a runtime exception occurs when you try it

这不起作用,因为Parent可能会动态实现-d,因此当您测试它而不是在字段中时,它会起作用。或者,Parent的实现可能会发生变化,因此此测试的结果不再正确。

显然是明智的回答2:

if ([super respondsToSelector:_cmd])
    [super d];

这不起作用,因为NSObject的-respondsToSelector实现将在Child中找到实现并在所有情况下都返回YES。

显然是明智的答案3:

if ([[self superclass] instancesRespondToSelector:_cmd])
    [super d];

当且仅当超类知道它总是实现-d时才有效;如果实例动态确定是否存在此方法,则此方法将不起作用。优于1,因为它将在运行时获取对Parent实现的静态更改。

显然是明智的回答4:

@try
{
    [super d];
}
@catch (NSException *exception)
{
    NSString *templateReason = [NSString stringWithFormat:
                                @"-[%@ %@]: unrecognized selector sent to instance %p"
                                ,NSStringFromClass([self superclass])
                                ,NSStringFromSelector(_cmd)
                                ,self];
    if (![exception.reason isEqualToString:templateReason])
        @throw exception;
}

如果超类中的方法不存在,那么性能很差,因为计算templateReason然后将其与异常原因进行比较是很昂贵的。

这种机制很脆弱,因为在这种情况下异常原因字符串的格式可以在将来的SDK或运行时版本中更改。

3 个答案:

答案 0 :(得分:5)

这些都不是必需的。

如果您是某个类或其他类的子类,则您需要知道是否要替换或补充行为。

换句话说,如果实现存在并且您希望以不同方式完成,则不要调用super。

如果实施不存在,则不要调用super。

如果 的实现存在,但您想要补充它,则称为super。

<强>附录:

执行情况随时可能发生变化与您的问题无关;重要的是接口是否会发生变化。

如果接口不断变化,那么这个类很难用于子类化,甚至是使用。

答案 1 :(得分:1)

不幸的是,我不知道这些答案是否合适。不幸的是,这归结为目的 - 它甚至可能不是你打算调用超类方法,有时候重写一个方法是替换方法,而不是在超类的功能之上链接你的功能。

归结为阅读文档并选择正确的方法。

如果这是关于您正在实施并希望使用一致方法的框架,那么2或3应该没问题。 1和4依赖于例外 - 除了objective-c中的真正特殊问题之外,它们并不真正用于任何事情。

答案 2 :(得分:-1)

在目标c中,您可以在协议中定义需要或可选的方法,但是您永远不能确定符合协议的类是否实际实现了该协议。

因此,您必须检查实例是否响应协议 我会选择选项2,这是最优雅的。 如果将来使协议方法可选,这仍然是正确的解决方案。

选项4我个人觉得很多Java-ish。