views:

77

answers:

2

I know of a couple of rules regarding Objective-C categories:

  1. Category methods should not override existing methods (class or instance)
  2. 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.

+7  A: 

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 another foo, is well defined. Any instance of MyClass will have a different foo than any instance of NSView that is not a MyClass, just as if foo had been defined in the main implementation and not a category. You should even be able to call [super foo] from MyClass to access the foo defined for NSView.

drawnonward
+4  A: 

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:

Category methods should not override existing methods (class or instance)

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.

Two different categories implementing the same method results in undefined behavior

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.

TechZen
+1 Thank you. That's a very good way of describing it. I have also changed the wording on rule #2 to match yours.
e.James