Objective-C has a feature called “categories” that allows you to extend the API of a type. It’s somewhat similar to extension methods in C# in that you can define methods which can be invoked on an instance of some class you don’t necessarily have the ability to modify. For example, you can add methods to NSString or NSArray. The differences, though, between extension methods and categories are quite revealing.
First off, the methods in a category are treated just like methods defined in the class targeted by the category. Instance methods in a category reference a ‘self’ pointer (similar to ‘this’ in C#) that points to the object of the target type. They can access private members of the target object. It looks and feels just like a normal instance method of the target type, only the method is defined in a separate file. You can also put class (static) methods in a category, which are invoked just like a class method of the target type.
Another thing to know about categories is that they can contain methods that override methods inherited from the target class’s base type(s). This is a strange concept at first, but it makes more sense once you know that categories are often used to break apart the implementation of large classes. Unlike extension methods in C#, which are rarely (if ever) used to implement core functionality of a class, categories are a great way to separate logical groups of methods into different source code files. You cannot add fields to a class from a category, but you can add as many methods as you want.
Now let’s see an example of categories in action. We’ll start with the demo app’s main function:
The Person class is declared in this header file:
It contains a getter and setter for the ‘name’ field. It also declares a method called sayHi. Note: Objective-C convention is to not prepend ‘get’ on a getter method if it returns a field, as seen above. Also, a class is allowed to have a method and a field with the same name. Now let’s look at how the Person class is defined in the .m file:
As you can see, that class does not define the eat: method invoked by main(). That’s where this demo’s category comes into play. The Consumption category is declared below:
First note that this file’s name is Person+Consumption.h. The naming convention is <class name>+<category name>.ext for files that contain categories. The @interface is followed by the target type; Person, in this example. Following that is the name of the category surrounded by parentheses. The body of the @interface contains declarations of the methods in the category. Now let’s see how the category is defined:
The category definition contains the eat: method declared previously, which is no surprise. It also contains an override of the init method inherited from NSObject. I doubt this is a good practice, but this at least proves it’s possible to override a method from a category.
Here is the result of running the demo program: