Sunday, February 20, 2011

IPhone– json serialization of custom objects

After shallow review of libraries, I got to start using the one of my current choice: json-framework.

In my instance, first usage of json libraries would not be fetching data from internet, but to save data to SQLite database in a “document” style.
Why I insist on SQLite instead of a simple file for a “document” based db? I just want my writes to be transactional, so if device shuts down during the write, I’m not going to have a corrupted file. Same if I’m suddenly killed by system.

I feel (but only checked in json-framework) that none of those json frameworks I reviewed a moment ago is capable of json to objective-c object mapping. Looks like there is a project doing this: https://github.com/yfactorial/objectiveresource. The project says it is a “A port of Ruby on Rails' ActiveResource to Objective-C (and specifically the iPhone)”. With last activity in October 2009, project is far from being active and overall looks like a sledgehammer for killing ants if used only for json to objective-c objects mapping.

Ok, it means that one would be back to encoding your very own objects to NSDictionaries and NSArrays in order to serialize them to json strings.

Here is a small example for my Environment class with name field and array of Plan objects. We are start with the inner most class, in my case Plan:

- (NSDictionary *) transformToDictionary
{

NSDictionary *body = [NSDictionary
dictionaryWithObjectsAndKeys: self.title, @"title", self.description, @"description",
self.author, "author", self.language, "lang", nil];

    return body;
}

Then in Environment I’d have:

- (NSDictionary *) transformToDictionary
{
    NSMutableArray *plansArray = [[NSMutableArray alloc] initWithCapacity:[plans count]];
    
    for (int i = 0; i < [plans count]; i++) {
        Plan *p = [plans objectAtIndex:i];
        [plansArray addObject:[p transformToDictionary]];
    }
    
    NSMutableDictionary *body = [NSMutableDictionary 
           dictionaryWithObjectsAndKeys: self.name, @"name", plansArray, @"plans", nil];
    [plansArray release];
    
    NSDictionary *envelope = [NSDictionary dictionaryWithObject:body forKey:@"environment"];
    
    return envelope;
}

Here I’m using the “wrapped” style of serialization where my environment will be a field of that resulting json anonymous object. dictionaryWithObjectsAndKeys is returning the autoreleased instance, that is why I’m not releasing in a caller method.

Given I have that implemented, here is how I retrieve a json string to put into “document” database:

        NSDictionary *envDict = [_environment transformToDictionary];
        NSString *envJson = [envDict JSONRepresentation];
        NSLog(@"%@", envJson);

Again, not releasing envDict here as it is autoreleased. Though I’m not an objective-c guru yet, so I just hope I’m right about that releasing thing.

With all that, here is my NSLog output:

{"environment":{"plans":[{"title":"Sample plan","description":"Sample plan description"}],"name":"Sample"}}

Enough to make me happy for a moment.

No comments: