6

子类扩展父类。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 或运行时版本中更改。

4

3 回答 3

5

这些东西都不是必需的。

如果您要对某个类或其他类进行子类化,则您已经需要知道您是在替换还是补充行为。

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

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

如果实现确实存在,但你想补充它,你调用 super。

附录:

实施是否可以随时更改与您的问题无关;重要的是界面是否发生变化。

如果接口不断变化,则该类很有可能是子类化甚至使用的极差候选者。

于 2011-11-23T13:58:20.107 回答
1

不幸的是,我不知道这些答案是否好。不幸的是,这归结为目的 - 它甚至可能不打算让您调用超类方法,有时覆盖方法是为了替换该方法,而不是将您的功能链接到超类的功能之上。

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

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

于 2011-11-23T13:57:32.500 回答
-1

在目标 c 中,您可以将协议中的方法定义为必需的或可选的,但您无法确定符合协议的类是否实际实现了该协议。

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

选项 4 我个人发现很多 Java 风格。

于 2011-11-23T13:59:49.543 回答