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

Phi*_*hby 6 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
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为Parent可能会动态实现-d,因此当您测试它而不是在字段中时,它会起作用.或者Parent的实现可能会更改,以便此测试的结果不再正确.

显然是明智的回答2:

if ([super respondsToSelector:_cmd])
    [super d];
Run Code Online (Sandbox Code Playgroud)

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

显然是明智的答案3:

if ([[self superclass] instancesRespondToSelector:_cmd])
    [super d];
Run Code Online (Sandbox Code Playgroud)

当且仅当超类知道它总是实现-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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

Wil*_*and 5

这些都不是必需的.

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

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

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

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

附录:

任何时候实施都可以改变,与您的问题无关; 重要的是如果界面发生变化.

如果界面不断变化,那么这个类很可能是一个非常差的候选子类,甚至可以使用.