【问题标题】:How do you know whether to invoke a superclass method in Objective C如何知道是否在 Objective C 中调用超类方法
【发布时间】:2011-11-23 13:51:11
【问题描述】:

子类扩展父类。 Parent 实现协议 C,该协议具有可选方法,包括 -(void)d。 Child 有一个-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 或运行时版本中更改。

【问题讨论】:

    标签: objective-c super respondstoselector


    【解决方案1】:

    这些都不是必需的。

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

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

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

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

    附录:

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

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

    【讨论】:

    • 这个答案不准确:假设超类实现了具有可选方法的协议,而您的子类实现了这些可选方法,您是否应该为这些可选方法调用超类?
    • @iMoses:您必须阅读相关课程的文档。
    • @WillihamTotland - 它并不总是可用的。 UITableViewController 符合 UIScrollViewDelegate。它是否实现了它的任何方法?不在 iOS 7 (afaik) 上,但谁知道 iOS 8 会发生什么?除此之外,可以编写动态添加或删除方法的代码,Objective C 是一种运行时语言,因此,这些功能是完全合法的。
    • @iMoses:尽管如此,我的回答仍然涵盖所有基础。诚然,它要求您一开始就知道所讨论的类是如何运作的,但是如果您不知道一个类的作用,那您为什么首先要对其进行子类化呢?
    【解决方案2】:

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

    归根结底是阅读文档并选择正确的方法。

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

    【讨论】:

      【解决方案3】:

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

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

      选项 4 我个人觉得很像 Java。

      【讨论】:

      • - (void)d 中调用[self d] 是一个非常糟糕的主意,大多数时候。
      • 我错过了阅读,它在 -d 的覆盖实现中,那么你应该调用 [super d]。如果它是实例 A 的另一个实例方法,我的意思是你应该调用 [self d]。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-21
      • 2012-04-04
      • 2020-01-26
      • 1970-01-01
      • 2015-12-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多