Advertisement

Learn Objective-C: Day 6

by
Student iconAre you a student? Get a yearly Tuts+ subscription for $45 →
This post is part of a series called Learn Objective-C.
Learn Objective-C: Day 5

In today's tutorial, you will learn about Categories and how to use them to extend the functionality of Cocoa-Touch classes. This is our final installment in the Learn Objective-C series, so you will also be provided with a quick recap on what we've covered so far and then look at what you can do to further your skills as an Objective-C or iPhone application developer.

Categories

So, what are categories? A lot of Objective-C tutorials and series will overlook categories, which is a shame as they're such a useful language feature that's amazingly useful. Categories help keep code clean and less cluttered by eliminating the need for unnecessary subclassing. From what we've learned so far, if we had an NSString object that we wanted to add functionality to do something like add a method that would replace all the 'a' characters with a '4' (useless I know, but for example purposes only), then we could subclass NSString and add the method ourselves. We also saw this kind of subclassing when we made our car class, I asked you at the end of that tutorial to make a subclass of car so you could add functionality to the base class. Subclassing is a good approach, and I am in no way telling you to stop subclassing, but, in certain situations, categories provide a better approach to add some extra functionality to a class.

Categories allow us to add methods to an existing class, so that all instances of that class in your application gain your functionality. For example, say we have 100 NSString objects in your app, but you'd like to make a custom subclass so each NSString has an extra method (reverseString for example). With categories we can simply add the method in a category and all instances will be allowed to use the new method. The syntax is obviously slightly different from subclassing and categories don't allow you to use instance variables. However, it is possible to overwrite a method already in place, but this should be done with caution and only if doing so is really necessary.

Syntax

Categories follow the same syntax layout as a class, as in they have an implementation and an interface. The interface looks like this:

@interface ClassNameHere (category)
	
// method declaration(s)

@end

The implementation looks like this;

@implementation ClassNameHere (category)
	
// method implementation(s)
	
@end

Example

Easy, right? So let's look at an example. We're going to make a simple method that will reverse a string. While this method is practically useless; it's not what the method is doing that's important. You should already know what the interface will look like, but here it is anyway:

@interface NSString (reverse)

-(NSString *) reverseString;

@end

Now to create our implementation:

@implementation NSString (reverse)

-(NSString *)reverseString {

}

@end

Next, we'll need to add some simple code to flip the string around. Since we're adding methods to the NSString class, we reference the string using self. Now in order to reverse the string we'll need a new, temporary string object to hold the reversed string. The way we will reverse the string is to simply loop through the existing string in reverse, each time we find a new character we'll add it to the reversed string object. The code for this is:

int length = [self length];
NSMutableString *reversedString;

reversedString = [[NSMutableString alloc] initWithCapacity: length];

while (length > 0) {
	[reversedString appendString:[NSString stringWithFormat:@"%C", [self characterAtIndex:--length]]];
}

return [reversedString autorelease];

This method is fairly simple, we're looping through once for each character in the string. We append the current character using stringWithFormat and the character (C) identifier. When we call --length we not only return the length integer, we also subtract from it too, which is how our loop moves along the string.

If all has gone well then all NSString's already in our project should adhere to our new category. Now you can see why categories are so useful!

Using Our Example

Ok, now all of our NSString objects should have our reverseString method. Just to recap, our code should look like this:

@interface NSString (reverse)

-(NSString *) reverseString;

@end

@implementation NSString (reverse)

-(NSString *)reverseString {
    int length = [self length];
    NSMutableString *reversedString;

    reversedString = [[NSMutableString alloc] initWithCapacity: length];

    while (length > 0) {
	    [reversedString appendString:[NSString stringWithFormat:@"%C", [self characterAtIndex:--length]]];
    }

    return [reversedString autorelease];
}

@end

Each block of code (interface and implementation) should be in their own respective files by convention. However, we name categories a little differently. The two files we have created are named: NSString+reverse.h (interface) and NSString+reverse.m (implementation).

This is a typical naming convention following the pattern of the name of the class we are adding a category to, a plus sign, and the name of our category. Before we continue, remember that we still need to include our header file into the main project. So now our code should look something like this:

NSString* testString = @"Just a test";

[testString reverseString];

NSLog(@"Reversed: '%@'", testString);

If all went according to plan, then the Console should log a reversed version of "Just a test"!

If all doesn't go according to plan, check to be sure you've copied the code for reverseString properly and make sure you're including the header (*.h) file for the category in your main code file.

As you can see, categories really are quite useful (especially with strings). They have a wide range of uses in any project, a common one I use is validation. This way I can keep all of my validation in one place and don't have to use any complicated subclasses.

Wrapping Up The Series

Not only is this the end of todays tutorial, this is the end of the series on the fundamentals of Objective-C. Over the last several tutorials we've covered the following topics:

  • Fundamentals of Programming
  • Fundamentals of OOP
  • Classes and Subclasses
  • Memory Management
  • Good Practice
  • Some Standard Naming Conventions

I hope you've enjoyed this series, and if you've only read one or two of the tutorials so far, then I encourage you to start at day 1 and read a tutorial a day. By the end of the series you should be confident enough to start writing your own code in just under a week!

If you have any questions about the series or examples shown, or if you would like an additional tutorial on another area of Objective-C programming, feel free to leave a comment below.

If you have any questions on Objective-C itself, a project that you're working on, or just some technical advice, don't hesitate to drop me a mention or direct message on Twitter or visit my website and find your way to the contact form!

Challenge

Now that we're finished, the challenges are endless. I highly suggest you put pen to paper and decide on a first app to build from start to scratch. Come up with an idea and a design, then apply all the principles you have learned from this series and let us know what you come up with!

Thanks for reading!