Using categories with core data

When I first started using Objective-C on the Mac language features such as categories and protocols were a mystery to me. You can go a long way without having to know anything about them but a small effort to grasp the key concepts can make a huge difference. Here is one example of how categories can make working with core data less of a pain.

The Xcode data modelling tool makes it pretty easy to create a core data model and then with one click generate the Objective-C class files for each entity in the model. The only disadvantage with this approach is that it can be a pain to manage if you need to add anything to the model class files. Each time you modify your core data model and regenerate all of the class files you need to merge your additions back into the new files.

Of course, there is a better way.

Objective-C Categories

Objective-C categories allow you to add new methods to an existing class without having to change the source code of the original class. In fact categories allow you to do this even if you do not have access to the original source. (This is not the same as subclassing in that you cannot add new instance variables to the class.)

The ability to split the implementation of a class across several source files is pretty useful when adding methods to a core data model class. We can keep the original generated files unmodified and place the additional methods in a separate file. Anytime the core data model changes we can regenerate all of the class files without worrying about overwriting our manual modifications.

Suppose I have a core data class named Item which, to keep things simple, has a single string property. The contents of the core data generated header file Item.h will be fairly minimal:

@interface Item : NSManagedObject
{
}

@property (nonatomic, retain) NSString *name;
@end

The actual implementation file Item.m is also pretty simple:

#import "Item.h"
@implementation Item
@dynamic name;
@end

Now suppose that I want to add a method to Item that will return the initial, uppercase letter of the name property. (A common enough requirement if I am displaying items in a sorted iPhone table view). By convention the filename used for the category is the name of the original class followed by a + followed by the category name. So in this example I could create a file named Item+Index.h as follows:

#import "Item.h";
@interface Item (Index)

- (NSString *)initialLetter;
@end

The implementation file Item+Index.m would look like this:

#import "Item+Index.h"
@implementation Item (Index)
- (NSString *)initialLetter {
    // return the first character of the name converted to uppercase
    return [[name substringToIndex:1] uppercaseString];
}
@end

That is all there is to it, anytime I want to use the added methods I import Item+Index.h instead of Item.h and I am done.