34

I need to serialize and deserialize objective-c objects into JSON to store in CouchDB. Do people have any example code for best practice for a general solution? I looked at a few JSON framework and they are stopped at the NSDictionary/NSArray level. i.e. A lot of framework will serialize and deserialize NSDictionary/NSArray into JSON. But I still have to do the work to convert NSDictionary into Objective-C objects.

To make things more complex, my Object A can have reference to an NSArray/NSDictionary of Object Bs.

My question is very similar to this question with addition of the collection requirement.

Instantiating Custom Class from NSDictionary

Community
  • 1
  • 1
PokerIncome.com
  • 1,708
  • 2
  • 19
  • 30
  • It's 2013 now and for some reason there seems to be no great answer for this. RestKit and other frameworks I've looked at seem to require a lot of "mapping" to be done, which makes no sense. Objects already describe themselves. – Fraggle Apr 08 '13 at 12:25
  • 1
    What frameworks are there for Json to NSOBbjects. I don't care if they stop at NSArray or NSDictionary. – user1898829 Apr 12 '13 at 10:44

7 Answers7

38

Finally we can solve this problem easily using JSONModel. This is the best method so far. JSONModel is a library that generically serialize/deserialize your object based on Class. You can even use non-nsobject based for property like int, short and float. It can also cater nested-complex JSON.

Considering this JSON example:

{ "accounting" : [{ "firstName" : "John",  
                    "lastName"  : "Doe",
                    "age"       : 23 },

                  { "firstName" : "Mary",  
                    "lastName"  : "Smith",
                    "age"       : 32 }
                              ],                            
  "sales"      : [{ "firstName" : "Sally", 
                    "lastName"  : "Green",
                    "age"       : 27 },

                  { "firstName" : "Jim",   
                    "lastName"  : "Galley",
                    "age"       : 41 }
                  ]}

1) Deserialize example. in header file:

#import "JSONModel.h"

@interface Person : JSONModel 
@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, strong) NSNumber *age;
@end

@protocol Person;

@interface Department : JSONModel
@property (nonatomic, strong) NSMutableArray<Person> *accounting;
@property (nonatomic, strong) NSMutableArray<Person> *sales;
@end

in implementation file:

#import "JSONModelLib.h"
#import "myJSONClass.h"

NSString *responseJSON = /*from example*/;
Department *department = [[Department alloc] initWithString:responseJSON error:&err];
if (!err)
{
    for (Person *person in department.accounting) {

        NSLog(@"%@", person.firstName);
        NSLog(@"%@", person.lastName);
        NSLog(@"%@", person.age);         
    }

    for (Person *person in department.sales) {

        NSLog(@"%@", person.firstName);
        NSLog(@"%@", person.lastName);
        NSLog(@"%@", person.age);         
    }
}

2) Serialize Example. In implementation file:

#import "JSONModelLib.h"
#import "myJSONClass.h"

Department *department = [[Department alloc] init];

Person *personAcc1 = [[Person alloc] init];
personAcc1.firstName = @"Uee";
personAcc1.lastName = @"Bae";
personAcc1.age = [NSNumber numberWithInt:22];
[department.accounting addOject:personAcc1];

Person *personSales1 = [[Person alloc] init];
personSales1.firstName = @"Sara";
personSales1.lastName = @"Jung";
personSales1.age = [NSNumber numberWithInt:20];
[department.sales addOject:personSales1];

NSLog(@"%@", [department toJSONString]);

And this is NSLog result from Serialize example:

{ "accounting" : [{ "firstName" : "Uee",  
                    "lastName"  : "Bae",
                    "age"       : 22 }
                 ],                            
  "sales"      : [{ "firstName" : "Sara", 
                    "lastName"  : "Jung",
                    "age"       : 20 }
                  ]}
Alphapico
  • 2,893
  • 2
  • 30
  • 29
  • Hi! Great example, I tried the same but when I add the object personSales1 (in the Serialize example), the department.sales is still nil. The same happens with department.accounting. How can I solve it? Do I have to initialize each NSMutableArray inside the Department Object? Many thanks! – jbartolome Jan 25 '14 at 04:07
  • I found my own solution: I had to initialize department.sales = [[NSMutableArray alloc] init]; to make it work. That drove me crazy for a lot of time! The same happens with department.accounting. Hope this helps to other people... – jbartolome Jan 25 '14 at 04:20
  • This is a really great library - but is it seriously sensitive to the input JSON using single quote vs double quote? – joelc Apr 15 '14 at 04:14
  • You need to initialise and cast the department.sales before using it. department.sales = (NSMutableArray*)[[NSMutableArray alloc] init]; – Ives.me Sep 04 '14 at 11:47
  • 1
    This makes you inherit all your model classes from `JSONModel` and that is not good at all. It's a restriction I'd avoid. – mato Jan 04 '16 at 23:38
  • toJSONString is what I need. Thank you – Ali Abbas Apr 04 '16 at 20:08
11

It sounds like you're looking for a serialization library that can let you convert objects of your own custom classes into JSON, and then reconstitute them back. Serialization of property-list types (NSArray, NSNumber, etc.) already exists in 3rd party libraries, and is even built into OS X 10.7 and iOS 5.

So, I think the answer is basically "no". I asked this exact question a month or two ago on the cocoa-dev mailing list, and the closest I got to a hit was from Mike Abdullah, pointing to an experimental library he'd written:

https://github.com/mikeabdullah/KSPropertyListEncoder

This archives objects to in-memory property lists, but as I said there are already APIs for converting those into JSON.

There's also a commercial app called Objectify that claims to be able to do something similar:

http://tigerbears.com/objectify/

It's possible I'll end up implementing what you're asking for as part of my CouchCocoa library, but I haven't dived into that task yet.

https://github.com/couchbaselabs/CouchCocoa

Jens Alfke
  • 1,946
  • 12
  • 15
8

You can easily add JSON capability to NSObject class with the help of NSDictionary,NSArray and NSJSONSerialization

Serialization:

Just see the example it will be very easy to understand.

Adding JSON Capability to NSObject Class:-

@interface JsonClassEmp : NSObject

@property(strong,nonatomic)NSString *EmpName,*EmpCode;

-(NSDictionary*)GetJsonDict;

@end

@implementation JsonClassEmp

@synthesize EmpName,EmpCode;

//Add all the properties of the class in it.
-(NSDictionary*)GetJsonDict
{
    return [NSDictionary dictionaryWithObjectsAndKeys:EmpName,@"EmpName",EmpCode,@"EmpCode", nil];
}

@end

JSON String Generator:-

In iOS 5, Apple introduced NSJSONSerialization, for parsing JSON strings so by using that we will generate JSON string.

-(NSString*)GetJSON:(id)object
{
    NSError *writeError = nil;

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:object options:NSJSONWritingPrettyPrinted error:&writeError];

    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

    return jsonString;
}

Moving towards Apple’s implementation is always safer to use since you have the guarantee that it will be maintained and kept up to date.

Way to use:-

- (void)viewDidLoad
{
    [super viewDidLoad];

    JsonClassEmp *emp1=[[JsonClassEmp alloc]init];

    [emp1 setEmpName:@"Name1"];

    [emp1 setEmpCode:@"1"];

    JsonClassEmp *emp2=[[JsonClassEmp alloc]init];

    [emp2 setEmpName:@"Name2"];

    [emp2 setEmpCode:@"2"];

    //Add the NSDictionaries of the instances in NSArray
    NSArray *arrEmps_Json=@[emp1.GetJsonDict,emp2.GetJsonDict];

    NSLog(@"JSON Output: %@", [self GetJSON:arrEmps_Json]);

}

Reference

Deserialization:

It's usual way of getting the deserialized data into NSDictionary or NSArray then assign it to class properties.

I am sure using the methods and ideas used above you can serialize & deserialize complex json easily.

Community
  • 1
  • 1
Durai Amuthan.H
  • 31,670
  • 10
  • 160
  • 241
4

You may want to try JTObjectMapping. Their description:

JTObjectMapping - Inspired by RestKit. A very simple objective-c framework that maps a JSON response from NSDictionary or NSArray to NSObject subclasses for iOS.

It's very small (unlike RestKit) and works great.

zekel
  • 9,227
  • 10
  • 65
  • 96
  • 1
    Thanks zekel! JTObjectMapping decouples mapping outside of the Model object, which allows you to use in any NSObject subclass, and cater cases where the API endpoints are not consistent with the data structure. I've also recently add support for underscores to CamelCases, which you'll never need to provide any mapping for this (e.g. full_name -> fullName) – James Tang Jun 20 '14 at 03:58
  • @JamesTang JTObjectMapping is very lightweight, but I can't get it to work with nested arrays of custom objects. – NKorotkov Feb 20 '16 at 14:58
2

I have a simple model class, which I wanted to turn into a JSON-Object.

For this purpose I added a „jsonData“-method to my model class: The method turns the model properties into foundation objects (int numbers into NSNumber objects etc.) Then a dictionary is populated with these objects and the corresponding keys (also the later JSON keys). After an (optional) check for validity, the JSON data object ist created with the NSJSONSerialization class „dataWithJSONObject“ method and returned.

- (NSData *)jsonData {

NSDictionary *root = @{@"Sport" : @(_sportID),          // I´m using literals here for brevity’s sake
                       @"Skill" : @(_skillLevel),
                       @"Visibility" : @(_visibility),
                       @"NotificationRange" : @(_notificationRange)};

if ([NSJSONSerialization isValidJSONObject:root]) {
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:root
                                    options:0
                                      error:nil];
    return jsonData;
}
return nil;

}

blauzahn
  • 351
  • 2
  • 6
2

This is possible using the RestKit library's object mapping system.

http://restkit.org/

1

Did you mean this? ;)

http://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSJSONSerialization_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40010946

Mirko Brunner
  • 2,204
  • 2
  • 21
  • 22
  • 3
    NSJSONSerialization only seriaizes/deserializes foundation objects, I think what is being asked for is a way to serialize/deserialize objects in your applications data model. RESTKit will do this but it's a heavy solution if all you want is the mapping it provides. – tapi Apr 27 '12 at 14:08