Dynamic classes with Objective-C
I recently worked on a project for a client that had a lot of data coming from a web service as JSON. The data was comprised of associative arrays (or dictionaries as they are known in other languages) with each key pointing to a set of data. Each of those sets of data can be used to instantiate one of several custom classes I created in Objective-C. Using TouchJSON from the handy TouchCode library I was able to translate the incoming JSON string to an NSDictionary object. An NSDictionary of data is much nicer than a raw string of JSON, but what I really wanted was to take each data set in the JSON and use it to initialize the custom classes I created.
My first pass at this was overly repetitive. I wrote a bunch of methods on my ResponseHandler class (which, as the name suggests, handles responses from the web service) that would consume each entry in the dictionary and return an instantiated object. So I had a bunch of methods on the ResponseHandler that looked like “newJSON”. Kind of messy if you ask me and I was not keeping in line with the DRY principle.
I did some digging into Objective-C and found that it is possible to do some nifty things with the language. One of them being dynamic class creation. With this new bit of knowledge, I had a clean way to resolve my lack of DRYness (…and incidentally, made me happy since I come from a Python background where dynamic class creation is relatively normal).
Lets take a contrived example of a web service which returns data about various shapes to the client. The JSON data retrieved from the web service can be used to instantiate two shape classes: Square and Circle.
If we make a request to this web service we get back the following JSON:
{'SquareObject': {'width': 10, 'height':10, 'center':[5,5]}, 'CircleObject': {'radius':10, 'center':[2,2]}}
Again, with TouchCode’s TouchJSON class, the JSON string above can be turned into cocoa objects.
The shape classes have the following interfaces:
@interface Square : NSObject { NSNumber *width; NSNumber *height; CGPoint center; } - (id)initWithJSON:(NSDictionary *)jsonData; @end @interface Circle : NSObject { NSNumber *radius; CGPoint center; } - (id)initWithJSON:(NSDictionary *)jsonData; @end
Notice I have a method on each class that has the same signature:
- (id)initWithJSON:(NSObject *)jsonData;
This method will be used to instantiate each class with the appropriate data.
The final setup requirement is to create a NSDictionary that maps the JSON keys to Class objects. It lives in my ResponseHandler class where I also instantiate the shape objects, but you can do this where ever makes sense for you.
NSDictionary *classMap = [NSDictionary dictionaryWithObjectsAndKeys: [Square class], @"SquareObject", [Circle class], @"CircleObject", nil];
In my ResponseHandler class, where I am instantiating the shapes from JSON, I iterate through the expected keys in the NSDictionary that was created from the JSON string (jsonData) and send the initWithJSON: message to each class like so:
NSMutableArray *tmpObjs = [[NSMutableArray alloc] init]; NSObject *anObj; for (NSString *aKey in [classMap allKeys]) { anObj = [[[classMap objectForKey:aKey] alloc] initWithJSON:[jsonData objectForKey:aKey]]; [tmpObjs addObject:anObj]; [anObj release]; } self.dataObjs = [NSArray arrayWithArray:tmpObjs];
That’s it. A relatively simple way to dynamically instantiate classes based on incoming data. If you want to see the complete program I used to write this program, you can find it here.

Thank you very much !!!, this is exactly what i was looking for.
Nice approach. I used TouchJSON as well, but I modified the CJSONDeserializer class by adding the method:
- (id)deserializeCustomObjects:(NSData *)inData withClassIdentifier:(NSString*)classIdentifier error:(NSError **)outError
Then in CJSONScanner in the scanJSONObject method I added a check at the end to see if the user wants custom objects, and that the outObject is an NSDictionary. If so I call my customObjectForDictionary method which looks like this:
{
// if the dictionary has a value for the customClassIdentifier we’ll try to
// create a custom object from it
if([theDictionary valueForKey:customClassIdentifier]) {
// we need to change the string into a class identifier
NSString *classname = [theDictionary valueForKey:customClassIdentifier];
Class class = objc_getClass([classname cStringUsingEncoding:NSASCIIStringEncoding]);
// test to see if the class is known to the Obj-C runtime
// and check to see if the class implements the needed method
if(class != NULL && [class respondsToSelector:@selector(objectFromDictionary:)]) {
// the class should return an autoreleased instance of itself
return [class objectFromDictionary:theDictionary];
}
}
return theDictionary;
}
This is the only approach I could come up with that made sense, and it has worked well for me. The main downside is that I have to keep my changes up to date with any changes in TouchJSON. The upside is that I keep all my custom object creation in one place.