Benjamin Martin

Categories for Extending a Core Class

Monday, July 15th, 2013

You want to add colors to the UIColor class. There are currently 15 different preset colors that can be used, but that's not good enough for you. You REALLY like yellow, and just yellowColor isn't going to cut it. You also want amber, aureolin, and citrine (thanks, Wikipedia). Instead of memorizing the RGB values and using them with colorWithRed every time, you want to be able to reference them by name with amberColor, aureolinColor, and citrineColor.

This is a perfect task for categories. Let's open Xcode. We'll start with a plain vanilla Single View Application:

Hit the "Next" button. Enter whatever you fancy for the product name, check "Use Storyboards" and "Use Automatic Reference Counting". Keep "Include Unit Tests" unchecked. When the project is ready to go, hit "Next" to create the project and create a new file with ⌘ + N. We're going to create an Objective-C category by navigating to Cocoa Touch in the left pane of the New File Window and selecting "Objective-C category":

In the "Category" field, enter something descriptive of what we're creating, perhaps "MoreYellow". The "Category on" field is more important. This is the class we will be adding functionality to. Begin typing "UIColor" and it should autocomplete for you:

If they're not already in there, go ahead and drag and drop these new "UIColor+MoreYellow.h" and "UIColor+MoreYellow.m" files into the "Supporting Files" folder for organizational purposes.

In our "UIColor+MoreYellow.h" file, we'll create the function prototype for the first new shade of yellow we want:

Notice this function has a + in front of it to denote it is a class method. Class methods are called upon a class instead of an instance variable of a class. What does this mean? Time for a little diversion.

Let's say we're setting the background color of our view. We would do this with the following:

self.view.backgroundColor = [UIColor redColor];

self is the current ViewController we are working with. redColor is a message being sent to (or a "method being called upon") the UIColor class.

Now let's say we want to get the number of items in an array. There is a message called count that will do this for us. However, we can't send the count message directly to the NSArray class because the NSArray class itself does not hold any items. It is merely a blueprint for NSArray instances (or "objects"). Only instances of NSArray can hold items. We could do the following:

Correct

NSArray *items = [[NSArray alloc] initWithObjects: @"first item", @"second item", nil];
NSLog(@"%d", [items count]);

Incorrect - the NSArray class itself doesn't hold any items.

NSLog(@"%d", [NSArray count]);

count is a message being sent to items, which is an instance of the NSArray class. In this case, count will return the value 2.

%d is the specifier for integers, which is what the count method returns (specifically a NSUInteger, or unsigned integer).

We just declared the function in "UIColor+MoreYellow.h". Now let's define the function in "UIColor+MoreYellow.m".

The RGB value for amber is (255, 190, 0). Because the colorWithRed method takes float values between 0 and 1, we have to divide our red, green, and blue values by 255.0. The red value is 255.0/255.0 = 1.0. The green value is 190.0/255.0. The blue value is 0/255.0 = 0. We'll repeat this process in the .h and .m files for aureolinColor and citrineColor using the appropriate RGB values:

We can now reference these colors in our ViewController.m file by simply importing "UIColor+MoreYellow.h":

Boom. The backgroundColor of our view is set to a random yellow color. The arc4random_uniform() function is the most true random number generator in Objective-C. Other functions such as arc4random() give results that are biased around powers of 2.

The full source for this post can be downloaded here or on Github.