Categories
Development

Objective-C Objects from JSON

I was asked recently how to create an Objective-C Object from a JSON result returned by a RESTful service. Man, that’s a mouthful.

It’s actually fairly easy, especially if you make use of the excellent JSONKit by John Engelhart. The example below does just that.

For starters I created a simple Cocoa Application and changed main() so it returns 0, because we don’t need to show a window and have an event loop. Here’s a link to the complete main.m.

Next add JSONKit.m and JSONKit.h to your project, and build. That’s it. It should just work.

Here’s what the code does.

For starters we define some sample JSON. This is very rudimentary. The object contains a firstName and lastName field. This is meant to represent the data returned by our pretend REST service.

static NSString* const kSampleJSON = @"{\"firstName\": \"Rob\", \"lastName\": \"Fahrni\"}";

Next up we define a Person interface.

@interface Person : 
    NSObject
{
@private
    NSString* _firstName;
    NSString* _lastName;
}

@property (copy) NSString* firstName;
@property (copy) NSString* lastName;

- (id)initWithDictionary:(NSDictionary*)dict;
- (void)dealloc;

@end

Again, very simple. This Person interface has first name(_firstName) and last name(_lastName) members and is initialized by passing it an NSDictionary*. So far, it looks pretty easy, right? Right!

The next thing we need to do is implement Person. Once again, no rocket science here. It’s straight Objective-C.

@implementation Person

@synthesize firstName = _firstName;
@synthesize lastName = _lastName;

- (id)initWithDictionary:(NSDictionary *)dict;
{
    if ((self = [super init]))
    {
        _firstName  = [dict valueForKey:@"firstName"];
        _lastName   = [dict valueForKey:@"lastName"];
    }
    
    return self;
}

- (void)dealloc;
{
    [_lastName release];
    [_firstName release];
    
    [super dealloc];
}

- (NSString*)description
{
    // Overriding description allows you to print something meaningful
    // to the debug output window. In this case we'll print 
    // Rob Fahrni.
    return [NSString stringWithFormat:@"%@ %@\n", _firstName, _lastName];
}

@end

Ah! Now we’re getting somewhere. Notice the Person is constructed with an NSDictionary* that should contain at least two entries; firstName and lastName. Note “firstName” and “lastName” just so happen to match our simple JSON constant, defined as kSampleJSON. That’s because it’s the source of our data.

Something else of note is the method description. By overriding NSObject description we allow NSLog to dump something meaningful when we give an instance of Person as an argument. You’ll see that used below. It’s darned handy when you’re debugging.

UPDATE 12/31/2011: I noticed I’d used objectForKey instead of valueForKey when assigning to _firstName and _lastName.

Finally we can test our code to see what it does.

int main(int argc, char *argv[])
{
    // Pretend like you've called a REST service here and it returns a string.
    // We'll just create a string from the sample json constant at the top
    // of this file.
    NSString* responseJSON = [NSString stringWithFormat:@"%@", kSampleJSON];
    
    // 1) Create a dictionary, from the result string,
    // using JSONKit's NSString category; objectFromJSONString.
    NSDictionary* dict = [responseJSON objectFromJSONString];
    
    // 2) Dump the dictionary to the debug console.
    NSLog(@"Dictionary => %@\n", dict); 
    
    // 3) Now, let's create a Person object from the dictionary.
    Person* person = [[[Person alloc] initWithDictionary:dict] autorelease];
   
    // 4) Dump the contents of the person object
    // to the debug console.
    NSLog(@"Person => %@\n", person);

    return 0;
}

That’s all there is to it? Yep, that’s it! Pretty simple, right?