如果两个 ObjC 类别重写相同的方法会发生什么?
我知道一些关于 Objective-C 类别的规则:
- 类别方法不应覆盖现有方法(类或实例)
- 两个不同类别对同一个类实现相同的方法将导致未定义的行为
我想知道当我覆盖自己的类别之一时会发生什么同一类别中的方法。例如:
@interface NSView (MyExtensions)
- (void)foo; // NSView category implementation
@end
@interface MyClass : NSView
{ }
@end
@interface MyClass (MyExtensions)
- (void)foo; // MyClass category implementation
@end
定义了这些接口后,当我运行以下代码时将执行哪个方法?
MyClass * instance = [[MyClass alloc] initWith...];
[instance foo];
[instance release];
注意:对于我的编译器,MyClass 实现优先,但我不确定是否一定会发生这种情况,或者只是一种特定的未定义行为。
I know of a couple of rules regarding Objective-C categories:
- Category methods should not override existing methods (class or instance)
- Two different categories implementing the same method for the same class will result in undefined behavior
I would like to know what happens when I override one of my own category methods in the same category. For example:
@interface NSView (MyExtensions)
- (void)foo; // NSView category implementation
@end
@interface MyClass : NSView
{ }
@end
@interface MyClass (MyExtensions)
- (void)foo; // MyClass category implementation
@end
With these interfaces defined, which method will be executed when I run the following code?
MyClass * instance = [[MyClass alloc] initWith...];
[instance foo];
[instance release];
Note: With my compiler, the MyClass implementation takes precedence, but I'm not sure if that is guaranteed to occur, or simply one specific flavor of undefined behavior.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
扩展一下前面的答案:
这是层次结构的问题。类别实际上只是组织源文件的一种方式。编译后,类的所有方法(包括任何类别中定义的方法)最终都位于同一个文件中。
您可以在常规类界面中执行的任何操作都可以在类别中执行,而您不应该在常规类界面中执行的任何操作都不应该在类别中执行。
所以:
您可以使用常规类接口中定义的方法来覆盖继承方法,以便您可以覆盖类别中的继承方法。
但是,您永远不会尝试在同一个普通接口中拥有两个相同的方法定义,因此您永远不应该在类别中拥有与普通接口或同一类上的另一个类别中的方法同名的方法。由于所有方法定义最终都在同一个编译文件中,因此它们显然会发生冲突。
应该重写为“两个不同的类别为同一个类实现相同的方法会导致未定义的行为。 同样,因为任何一个类的所有方法最终都在同一个文件中,所以在同一个类中拥有两个方法显然会导致奇怪的情况。
您可以使用类别来提供覆盖超类方法的方法,因为类及其超类是两个不同的类。
如果您对某个类别是否会导致问题感到困惑,只需问问自己:“如果我将类别中的方法全部复制并粘贴到类的 .h/.m 文件中,该类别中的方法会起作用吗?”如果答案是“是”,那么您就没有问题了。如果“否”,那么你就有问题了。
To extend on drawnonward answer:
It's matter of hierarchy. Categories are really just a means of organizing source files. When compiled, all the methods of a class, including the ones defined in any category, end up in the same file.
Anything you could do in a regular class interface you can do in a category and anything you shouldn't do in a regular class interface you shouldn't do in a category.
So:
You can use methods defined in the regular class interface to override inherited methods so you can override inherited methods in a category.
However, you would never try to have to two identical method definitions in the same ordinary interface so you should never have a method in a category that has the same name as a method in either the ordinary interface or another category on the same class. Since all the method definitions end up in the same compiled file, they would obviously collide.
That should be rewritten to say "Two different categories implementing the same method for the same class results in undefined behavior." Again, because all the methods for any one class end up in the same file, having two methods in the same class would obviously cause weirdness.
You can use categories to provide methods that override superclass methods because a class and its superclass are two distinct classes.
If your ever confused about whether a category will cause problem just ask yourself this: "Would the methods in the category work if I copied and pasted them all into the class' .h/.m files?" If the answer is "yes" then you're in the clear. If "no", then you've got problems.
每个类的每个方法都有一个实现。类别添加或替换特定类的方法。这意味着您所看到的行为(其中 MyClass 有一个
foo
而 NSView 有另一个foo
)是明确定义的。 MyClass 的任何实例都将具有与任何非 MyClass 的 NSView 实例不同的foo
,就像foo
是在主实现中定义的而不是类别一样。您甚至应该能够从 MyClass 调用[super foo]
来访问为 NSView 定义的foo
。Each method of each class has an implementation. A category adds or replaces a method for a specific class. That means the behavior you are seeing, where MyClass has one
foo
and NSView has anotherfoo
, is well defined. Any instance of MyClass will have a differentfoo
than any instance of NSView that is not a MyClass, just as iffoo
had been defined in the main implementation and not a category. You should even be able to call[super foo]
from MyClass to access thefoo
defined for NSView.