Objective C 中如何知道是否调用超类方法
子类扩展了父类。父级实现协议 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 或运行时版本中更改。
Class Child extends Parent. Parent implements protocol C which has optional methods, including -(void)d
. Child has an implementation of -d
; should it invoke [super d]
?
In other words, what code do I write to invoke [super d]
if and only if something will respond to it? Assume that I do not control the implementation of Parent; it may change at any time.
Here are all the ways I have thought of. I am currently using number 4.
Apparently sensible answer 1:
[super d]; // Delete this line if a runtime exception occurs when you try it
This does not work because Parent might implement -d dynamically so this works when you test it and not in the field. Or the implementation of Parent could change so that the result of this test is no longer correct.
Apparently sensible answer 2:
if ([super respondsToSelector:_cmd])
[super d];
This does not work, because NSObject's implementation of -respondsToSelector will find the implementation in Child and return YES in all cases.
Apparently sensible answer 3:
if ([[self superclass] instancesRespondToSelector:_cmd])
[super d];
This works if and only if the superclass knows it always implements -d; if instances dynamically determine whether this method is present this technique will not work. Better than 1 in that it will pick up static changes to the implementation of Parent at runtime.
Apparently sensible answer 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;
}
Performance of this is poor if the method in the superclass does not exist because computing templateReason and then comparing it to the exception reason is expensive.
This mechanism is fragile because the format of the exception reason string in this case could be altered in a future SDK or runtime release.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这些都是不必要的。
如果您要对某个类或其他类进行子类化,则您已经需要知道您是否正在替换或补充行为。
换句话说,如果实现存在并且您希望以不同的方式完成它,则您不会调用 super.
如果实现不存在,则不会调用 super。
如果实现确实存在,但您想补充它,您可以调用 super.
附录:
实施是否可以随时更改与您的问题无关;重要的是界面是否发生变化。
如果接口不断变化,那么该类很可能非常不适合子类化,甚至不适合使用。
None of these things are necessary.
If you are subclassing some class or other, you already need to know if you are replacing or supplementing behavior.
In other words, if the implementation exists and you want it done differently, you don't call super.
If the implementation doesn't exist, you don't call super.
If the implementation does exist, but you want to supplement it, you call super.
Addendum:
Wether the implementation can change at any time isn't relevant for your question; what is important is if the interface changes.
If the interface is constantly changing, odds are good the class is an exceptionally poor candidate for subclassing, or even use.
不幸的是,我不知道这些答案是否好。不幸的是,这归结为目的 - 它甚至可能不是为了让您调用超类方法,有时重写方法是为了替换该方法,而不是将您的功能链接到超类的功能之上。
归根结底是阅读文档并选择正确的方法。
如果这是关于您正在实现的框架并且希望使用一致的方法,那么 2 或 3 应该没问题。 1 和 4 依赖于异常 - 除了 Objective-C 中真正的异常问题之外,这些异常并没有真正的用途。
Unfortunately I am not whether any of these answers are good. Unfortunately this comes down to purpose - it may not even be intended for you to call the superclass method, sometimes overriding a method is about replacing the method, not chaining your functionality on top of the superclass's functionality.
It comes down to reading the documentation and choosing the right approach.
If this is about a framework that you are implementing and wish to use a consistent approach, then 2 or 3 should be fine. 1 and 4 rely on exceptions - which are not really intended to be used for anything except truly exceptional issues in objective-c.
在 Objective C 中,您可以将协议中的方法定义为必需或可选,但您永远无法确定符合协议的类是否实际上实现了该协议。
因此,您始终必须检查实例是否响应协议。
我会选择选项2,这是最优雅的。
当您将来将协议方法设为可选时,这仍然是正确的解决方案。
我个人认为选项 4 很像 Java。
In objective c you can define methods in protocols to be required or optional, but your never sure if a class that is conform to a protocol, actually implements that protocol.
So you always have to check if the instance responds to a protocol.
I would choose for option 2, this is the most elegant.
When you will make the protocol method optional in the future, this will still be the correct solution.
Option 4 I personally find to much Java-ish.