Categories: Modifying Existing Classes in Objective-C

One of the more interesting features of some scripting languages is the programmer’s ability to modify existent–and sometimes even built-in–classes. It can be used to segment functionality in a large class, split source for one class between several files, and add convenience methods.

Objective-C also has this capability through the use of Categories.

For an example of where this might get used: I found early on that I missed the convenience of Java’s String.trim() method, which would strip the whitespace from both sides of the String and return a new object. Python and Ruby have str.strip() and String.strip, respectively.

In Objective-C we have a similar tool that is very powerful: [NSString stringByTrimmingCharactersInSet:] which takes a NSCharacterSet as an argument. To trim all of the whitespace, I would say:

[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]

To trim a specific group of characters, I might call:

[self stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:myString]]

This is quite verbose, and (as a trivial example goes) and requires putting together several method calls for what is (for me, anyways) a very common tasks. So for our example, I’ll add methods for these functions to NSString.

There are three parts for adding a Category to NSString:

  1. Create a header file for the interface.
  2. Create the implementation file.
  3. Import the header file where I want to use the modified class (purely optional).

Header File

Using the convention suggested by Apple and others, I have chosen to name my header file NSString+NGTrim.h, where NSString is the base class that I am modifying and NGTrim is the name I have chosen for my Category.

1
2
3
4
5
6
@interface NSString ( NGTrim ) 
 
- (NSString *) stringByTrimmingWhitespace;
- (NSString *) stringByTrimmingCharacters:(NSString *)trim;
 
@end

If I wanted to go for extreme brevity, I could just use the method names trim and trimCharacters:, but here I decided to go with something closer to Apple’s naming convention.

The first line is @interface NSString ( NGTrim ) and serves to declare the category. It follows the format @interface BaseClassName ( CategoryName ).

After that come the method names, it is worth noting that we can add methods only and cannot actually change the member variables without subclassing.

Implementation File

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import "NSString+NGTrim.h"
 
 
@implementation NSString ( NGTrim )
 
- (NSString *) stringByTrimmingWhitespace {
	return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
 
- (NSString *) stringByTrimmingCharacters:(NSString *)trim {
	return [self stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:trim]];
}
 
@end

This is a standard implementation file.

Usage

#import "NSString+NGTrim.h" //Optional
 
...
 
[@"\t\tTest!\t\t" stringByTrimmingWhitespace];

The methods are now available and can be called from any NSString object in our program.

When we are ready to use our modified class we may optionally call #import “NSString+NGTrim.h”. The new methods will function just fine and will be visible at runtime without the import, but at compile time we will see a warning that “‘NSString‘ may not respond to ‘-stringByTrimmingWhitespace‘.”

I would generally consider importing such files a Best Practiceâ„¢ for the sake of documentation, warning management, and code cleanliness.

Conclusion

Objective-C gives us a powerful way to segment our classes, add additional functionality, and add convenience methods to existent classes. However, given the power of Categories and their potential for abuse, it is probably a good idea to discuss any modifications to common libraries or core classes (especially NSObject) with your team, and making good use of folder layout so that the modifying files are easily found.

Further Reading

This entry was posted in Uncategorized. Bookmark the permalink.

Error: The ad management script is not properly configured for this user

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>