PrEV
Thoughts from a NeXTStep Guy on Cocoa Development

Core Data Code Generation

Sep 08, 2009 by Bill Dudney

When building Core Data applications you can choose to use the NSManagedObject class for most of your entities, but from time to time you need to have a custom class to add custom code to. You might want to do lazy initialization of transient attributes, validation of the instance, or any number of other things you need to do with instances of your Core Data classes (they are Objective-C objects after all).

When you start adding custom code to your classes maintenance becomes a hassle, when you add an attribute you can either manually keep your custom classes in sync or regenerate the code. When you regenerate Xcode kindly keeps the old version of your code (if you click the right button) but you have to manually merge your custom code back into the freshly generated code. The manual merge is almost always a piece of cake but it can still be a time sink to have to do that with each new attribute you add. So I use categories to manage my custom code and make the regeneration of classes a snap.

Categories, for those that don't know, are a way to extend existing classes in the Objective-C runtime. A category can be thought of as a bag of methods that are added to a class when the category is loaded (of course the real technical details are a bit more complex). So I put all my custom code into a category that I typically call 'Custom' in a separate files named ClassName+Custom.h and ClassName+Custom.m. That way when the main class is regenerated I don't have to manually merge the custom code back into my generated code.

Here is the interface for a Movie class that we could persist via Core Data.

#import 
@interface Movie : NSManagedObject {
}

@property(nonatomic, retain)NSString *name;

@end

And here is the 'Custom' category interface for the Movie class.

#import "Movie.h"

@interface Movie (Custom)
- (void)play;
@end

What this is saying to the compiler is that we have a new method 'play' that will be added to the Movie class at runtime when this category is loaded. If you import Movie+Custom.h instead of Movie.h you will be able to use this play method without compiler warnings.

The implementation of the Movie class is simple, its just got the @dynamic statement in the implementation block. The category implementation looks like this.

#import "Movie+Custom.h"

@implementation Movie (Custom)

- (void)play {
  NSLog(@"playing %@", self.name);
}

@end

This implementation block provides the code for the play method and is what gets added to the Movie class at runtime.

You have to, of course, be careful with Categories because you can get into trouble. For example, what happens if you replace a method on the main class with a method in the category? I'll leave that between you and the docs. But don't be afraid of this sort of straightforward usage of categories, it can make your life much easier.

Hope this helps your usage of Core Data to be even better.



Comments:

Hi Bill. You should check Mogenerator.
It’s a command-line tool that automates the generation of custom subclasses. Point it at your .xcdatamodel file and it will spew out four files per entity, two for you, two for the machine. (From Jonathan 'Wolf' Rentzsch website http://rentzsch.com/code/mogenerator) and http://github.com/rentzsch/mogenerator/tree/master

Posted by Anthony Mittaz on September 09, 2009 at 04:09 AM MDT #

Echoed. The pattern you're describing provides great benefits, but ad-hoc categories are no match for consistent autogenerated superclasses, which mogenerator provides in a blink.

Posted by Nat Irons on September 09, 2009 at 10:58 AM MDT #

Post a Comment:
  • HTML Syntax: Allowed