Categories in Objective-C

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:

To learn more about categories, check out this blog post and the official docs from Apple.

This entry was posted in Objective-C. Bookmark the permalink.

7 Responses to Categories in Objective-C

  1. Johan O says:

    Nice to follow you in this Josh, i have been following your WPF blog and has recently began looking at Objective-C on the Mac (for iphone development) at the same time you did, which is fun!

    I have actually read the same book that you did, and I thought it was a really good book, straight to the point.

    About that retain, release thing in your setName, can’t you just use properties (with the retain attribute) to avoid having to write that in your set property? Or is that not possible when using categories?

    Looking forward to reading about your findings. One of the things I like with Cocoa right now is the notification system, which looks a lot like the Messenger you wrote for the MVVM foundation.

    • Josh Smith says:

      I could have use a property, but chose not to for this demo. I’m saving properties for an upcoming blog post. 🙂

      Josh

  2. Devin Brown says:

    Great post Josh!

    Another interesting mention is that you can use categories to override the style of built in controls, such as UINavigationController. As an example, the red UINavigationController of Yelp’s iPhone app could be achieved by adding the following:

    @implementation UINavigationBar (UINavigationBarCategory)

    – (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
    {
    if([self isMemberOfClass: [UINavigationBar class]]){
    UIImage *image = [UIImage imageNamed:@”RedNavBar”];
    CGContextClip(ctx);
    CGContextTranslateCTM(ctx, 0, image.size.height);
    CGContextScaleCTM(ctx, 1.0, -1.0);
    CGContextDrawImage(ctx, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), image.CGImage);
    }else{
    [super drawLayer:layer inContext:ctx];
    }
    }

    @end

    So keep in mind that you can also override the methods contained in the controller’s superclass as well, to get even more granular control.

  3. Darren Oster says:

    Hi Josh,
    Is there a reason you used [self setName:nil] rather than [name release] in Person’s dealloc method? Due to the logic in the setName method it does the same thing, but just calling release is (infintesimally) faster and you don’t need to worry about any strange logic that may or may not be within the setter.

  4. Pingback: Anonymous categories to the rescue | iJoshSmith

Comments are closed.