Jason R. Anderson

Software Engineer & UX Designer

Better Objective-C Code Management Through Categories

My good friend and colleague, Will Towe, recently inherited a code base with a peculiar class listed in the Xcode file inspector. The dubious Utils class. This is not the first time Will or myself have come across the infamous Utils.h/.m catch-all, and I doubt it will be the last. But hopefully, the words in this blog and the many more like it will eventually fall on the ears of budding Objective-C programmers and they will avoid this pattern.

So, What is this Utils Class of Which You Speak?

To put it plainly, the Utils class is typically a whole bunch of class methods for different classes meant to add functionality to those classes. For example, you might have a class method in Utils that takes a hexadecimal string and converts it to a UIColor, or maybe a convenience method that crops a UIImageView into a circle. The intent is noble, but the implementation leaves much to be desired.

The Problem with the Utils Class

It’s absolutely the right thing to do, building out convenience methods for existing classes without subclassing, but there are a few problems with dumping all that effort into a catch-all class like Utils. First of all, it obfuscates your intent. The Utils class is a simple NSObject however, it concerns itself with the extension of any other class the developer deems fit to extend, be it NSString or NSArray. This makes it unclear as to whether an object the developer is working with has any extended functionality without combing through the Utils class. Secondly, this Utils class will continue to grow over the life of the project and can become unwieldy. Not to mention, taking advantage of its extensions means you have to import all that extra code for every object it manages, regardless of whether you want to or not.

Enter the Objective-C Category

Luckily, Objective-C already has a reasonable, manageable way to extend classes without subclassing and it’s with categories. For example, NSArray has a nice built-in property for getting the last object in an array [myArray lastObject] that does so by first checking to make sure the array isn’t empty before returning the object. This is a great convenience method because, as you probably know, calling [myArray objectAtIndex:myArray.count-1] will crash if you try it on an empty array. Calling the lastObject getter means you can avoid the initial check to see whether the array contains objects or not. Oddly enough, NSArray has had the lastObject property since forever, but only added a firstObject method in the past few years. Prior to the addition of firstObject, this was a prime target for creating a category.

How to Create a Category

For an example, we’re going to create a simple category on UIColor to create a color from a hexadecimal string. To create a category in Xcode, select File->New->File… (or ⌘N from the keyboard). In the dialog box, choose Source->Objective-C File and then click Next.

Step 1

Add a name for the file (I like to prefix my categories with my initials and then name the file extensions, e.g. JRAExtensions), set File Type: to Category, and choose UIColor from the Class: drop down menu. Click Next and then save the file to your project directory.

Step 2

You should now see the .h and .m files with the Category naming convention (e.g. class+filename.h and class+filename.m).

Step 3

Open the .h file and add the following class method:

+ (UIColor *)JRA_colorWithHexadecimalString:(NSString *)hexadecimalString;

By convention, you should prefix your methods (in my case, I like to use my initials and an underscore). Since Objective-C doesn’t have the notion of name-spacing, naming conflicts can be a problem. Imagine you wrote your own [NSArray firstObject] extension and then Apple came along and wrote one using the same name, like they actually did a few years ago when they added the firstObject property to NSArray.

Now, in the .m file, write the implementation for the method:

+ (UIColor *)JRA_colorWithHexadecimalString:(NSString *)hexadecimalString {
    if (hexadecimalString.length == 0) {
        return nil;
    }
    
    hexadecimalString = [hexadecimalString stringByReplacingOccurrencesOfString:@"#" withString:@""];
    
    UIColor *retval = nil;
    NSScanner *scanner = [NSScanner scannerWithString:hexadecimalString];
    
    uint32_t hexadecimalColor;
    if (![scanner scanHexInt:&hexadecimalColor]) {
        return retval;
    }
    
    uint8_t red = (uint8_t)(hexadecimalColor >> 16);
    uint8_t green = (uint8_t)(hexadecimalColor >> 8);
    uint8_t blue = (uint8_t)hexadecimalColor;
    
    retval = [UIColor colorWithRed:(CGFloat)red/0xff green:(CGFloat)green/0xff blue:(CGFloat)blue/0xff alpha:1.0];
    
    return retval;
}

Now, whenever a designer passes you a list of hexadecimal colors for your next design comp, you have a handy method on UIColor that you can use instead of calculating the red/blue/green values ahead of creating your color. Just import the UIColor+JRAExtensions.h file into your class and call:

UIColor *darkRedColor = [UIColor JRA_colorWithHexadecimalString:@"#990000"];