18
votes

A class can be extended in Objective C using a category such as:

@interface NSString (CategoryName)
-(NSString *)myFabulousAddition;  // a fabulous additional method
@end

/////////////////////////////
@implementation NSString (CategoryName)

-(NSString *)myFabulousAddition {
    // do something fabulous...

}
@end

In this small example, I would be adding the method myFabulousAddition to NSString. I could then call it by [anNSString myFabulousAddition] just as if it were part of the NSString set of methods. Great and useful.

In the Apple documents regarding Categories, the docs state:

There’s no limit to the number of categories that you can add to a class, but each category name must be different, and each should declare and define a different set of methods.

What if you have something like this:

@interface NSString (CategoryName)
-(NSString *)myFabulousAddition;  // a fabulous additional method
@end

@interface NSString (ANOTHERCategoryName)
-(NSString *)myFabulousAddition;  // a DIFFERENT fabulous additional method 
                                  // BUT with same name as the other category
@end


/////////////////////////////

@implementation NSString (CategoryName)

-(NSString *)myFabulousAddition {
    // do something fabulous...

}
@end
@implementation NSString (ANOTHERCategoryName)

-(NSString *)myFabulousAddition {
    // do something equally fabulous, but DIFFERENT...

}
@end

The lack of a name in the parenthesis indicates that the form is an extension to the class, like so:

@interface MyObject ()   // No name -- an extension vs category to MyObject
- (void)setNumber:(NSNumber *)newNumber;
@end

Does the category name have any meaning to the compiler or linker? Is the category name part of the method signature in anyway or is it part of a primitive namespace? If the category name is meaningless, how do you know if you are about to stomp on another method and get undefined behavior?

5

5 Answers

7
votes

The way to avoid stomping on methods is to prefix your category method names, like this:

@interface NSString (MyCompanyCategoryName)

- (NSString *)MYCO_fabulousAddition;

@end

If you get a collision of method names from different categories, then which one 'wins' at run time is completely undefined.

The name of a category is almost entirely useless, with the exception being that the nameless category (i.e. ()) is reserved for class extensions. Methods from class extensions are supposed to be implemented in the class' main @implementation.

3
votes

The category name doesn't mean anything special, it's just an identifier. Unless the linker (or runtime loader) decides to give you a warning, there is no way to tell that multiple categories are defining the same method.

1
votes

The behavior is (largely) unpredictable - one of the categories will win out, but you can't tell which one. Also, I think it's well possible you will start out with one implementation and end up with another one (if the second category is loaded after the first).

1
votes

It certainly acts as an identifier, from the programmer's point of view. In the compiler point of view category methods are simply added as an extension of the class ( from which it is extending), regardless of the name.

And yes you can add categories of the same class with the same identifiers, even with same functions. But you definitely can't override any function because categories are just part of the class once you define them ( Just like you can't override a function of a class from within that class ).

As they are being added at runtime, they don't raise any error and only at runtime compiler selects the function, which is totally unpredictable.

0
votes

i believe that they don't have any meaning. You don't really use them in your code ... Since they are categories and ... the semantic of a category ... is just to categorize something, i think this is somewhat logical ... I would say they just simply gather the methods ...

On the other hand your question is very valid ... You DON'T KNOW if you override a method. If you are in the same project then the compiler issues a warning (or an error ? i don't remember), however if you are overriding a method from a library, then .. you are out of luck ...