Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cocoa: deserialize json string to custom objects (not NSDictionary, NSArray)

In java-land, there are a handful of useful libraries which will convert json strings to objects of matching type. The json libraries I've seen for cocoa simply create nested NSDictionaries and NSArrays. Is there a tool out there which will go the extra step of reconstituting whatever object type I want?

So, for example, if I have a class called "Unicorn", with a property "maneColor", and I have json that looks like this:

{
 "maneColor":"silver"
}

I can automatically instantiate a Unicorn object with "maneColor" set to "silver".

like image 515
morgancodes Avatar asked Apr 23 '11 01:04

morgancodes


2 Answers

I'm not aware of any specific implementations, but key-value coding gets you very close to what you want: Key Value Coding Guide. I've had good results combining streamed json parsing with KVC.

The -setValue:forKey: method makes adapting serialized data to custom objects fairly straightforward. To continue with your example, you'd create a Unicorn class with all required accessor methods: -setName:/-name, -setManeColor/-maneColor, etc. (You may be able to use properties for some expected values, but there are cases, as with the maneColor value, where you probably want to write a custom setter to convert from the color name string to an NSColor or UIColor object.)

You'll also want to add two more methods to your custom object: -setValue:forUndefinedKey: and -valueForUndefinedKey:. These are the methods that will be called if your object has no accessor methods matching a key passed into the KVC methods. You can catch unexpected or unsupported values here, and store them or ignore them as necessary.

When you send -setValue:forKey: to the Unicorn object, the framework looks for accessors matching the key pattern. For instance, if the key is "maneColor" and you're setting the value, the framework checks to see if your object implements -setManeColor:. If so, it invokes that method, passing in the value; otherwise, -setValue:forUndefinedKey: is called, and if your object doesn't implement it, an exception is thrown.

When your parser's delegate receives notification that parsing a json unicorn object has begun, instantiate a Unicorn object. As your parser returns the parsed data to you, use -setValue:forKey: to add the data to your object:

- ( void )parserDidBeginParsingDictionary: (SomeParser *)p
{
     self.currentUnicorn = [ Unicorn unicorn ];
}

- ( void )parser: (SomeParser *)p didParseString: (NSString *)string
          forKey: (NSString *)key
{
    [ self.currentUnicorn setValue: string forKey: key ]
}

- ( void )parserDidFinishParsingDictionary: (SomeParser *)p
{
    [ self.unicorns addObject: self.currentUnicorn ];
}
like image 133
more tension Avatar answered Nov 16 '22 01:11

more tension


Use Jastor - https://github.com/elado/jastor Takes already parsed JSON into NSDictionary and fills an instance of real Objective-C class.

NSDictionary *parsedJSON = (yajl, JSONKit etc)
Unicorn *unicorn = [[Unicorn alloc] initWithDictionary:parsedJSON];

unicorn.maneColor // "silver"
like image 38
elado Avatar answered Nov 16 '22 02:11

elado