19

I'd like to JSON-serialize my own custom classes. I'm working in Objective-C / iOS5. I'd like something to do the following:

Person* person = [self getPerson ]; // Any custom object, NOT based on NSDictionary
NSString* jsonRepresentation = [JsonWriter stringWithObject:person ];
Person* clone = [JsonReader objectFromJson: jsonRepresentation withClass:[Person Class]];

It seems that NSJSONSerialization (and several other libraries) require the 'person' class to be based on NSDictionary etc. I want something that will serialize any custom object that I care to define (within reason).

Let's imagine Person.h looks like this:

#import <Foundation/Foundation.h>
@interface Person : NSObject 
@property NSString* firstname;
@property NSString* surname;
@end

I'd like the generated JSON for an instance to look similar to the following:

{"firstname":"Jenson","surname":"Button"}

My app uses ARC. I need something that will both serialise and deserialize using objects.

Many thanks.

Journeyman
  • 10,011
  • 16
  • 81
  • 129
  • 1
    If you could get the attributes list, you could iterate them invoking the valueForKey: method to get its content and fill in a dictionary... It seems you will be able to do so with class_copyPropertyList() and some other strange methods. This may help: http://stackoverflow.com/questions/754824/get-an-object-attributes-list-in-objective-c Good luck! – Ricard Pérez del Campo May 09 '12 at 11:59
  • This link helps you.....[http://stackoverflow.com/a/29095726/3177007](http://stackoverflow.com/a/29095726/3177007) – Mohamed Jaleel Nazir Mar 17 '15 at 09:48

5 Answers5

23

This is a tricky one because the only data you can put into JSON are straight up simple objects (think NSString, NSArray, NSNumber…) but not custom classes or scalar types. Why? Without building all sorts of conditional statements to wrap all of those data types into those type of objects, a solution would be something like:

//at the top…
#import <objC/runtime.h>

    NSMutableDictionary *muteDictionary = [NSMutableDictionary dictionary];

    id YourClass = objc_getClass("YOURCLASSNAME");
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(YourClass, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        SEL propertySelector = NSSelectorFromString(propertyName);
        if ([classInstance respondsToSelector:propertySelector]) {
            [muteDictionary setValue:[classInstance performSelector:propertySelector] forKey:propertyName];
        }
    }
    NSError *jsonError = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:muteDictionary options:0 error:&jsonError];

This is tricky, though because of what I stated before. If you have any scalar types or custom objects, the whole thing comes tumbling down. If it's really critical to get something like this going, I'd suggest looking into investing the time and looking at Ricard's links which allow you to see property types which would assist on the conditional statements needed to wrap the values into NSDictionary-safe objects.

SushiGrass Jacob
  • 19,425
  • 1
  • 25
  • 39
17

Now you can solve this problem easily using JSONModel. 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.

Deserialize example. By referring to your example, in header file:

#import "JSONModel.h"

@interface Person : JSONModel 
@property (nonatomic, strong) NSString* firstname;
@property (nonatomic, strong) NSString* surname;
@end

in implementation file:

#import "JSONModelLib.h"
#import "yourPersonClass.h"

NSString *responseJSON = /*from somewhere*/;
Person *person = [[Person alloc] initWithString:responseJSON error:&err];
if (!err)
{
   NSLog(@"%@  %@", person.firstname, person.surname):
}

Serialize Example. In implementation file:

#import "JSONModelLib.h"
#import "yourPersonClass.h"

Person *person = [[Person alloc] init];
person.firstname = @"Jenson";
person.surname = @"Uee";

NSLog(@"%@", [person toJSONString]);
Alphapico
  • 2,893
  • 2
  • 30
  • 29
1

maybe this can help JLObjectStrip.

its the same as what jacob said but it iterates even to the property of the class. this will give you dictionary/array then just use sbjson/jsonkit or what ever you prefer to construct your json string.

Joshua
  • 2,432
  • 1
  • 20
  • 29
0

Try this one BWJSONMatcher

It's really simple as well as convenient.

...
NSString *jsonString = @"{your-json-string}";
YourValueObject *dataModel = [YourValueObject fromJSONString:jsonString];

NSDictionary *jsonObject = @{your-json-object};
YourValueObject *dataModel = [YourValueObject fromJSONObject:jsonObject];
...
YourValueObject *dataModel = instance-of-your-value-object;
NSString *jsonString = [dataModel toJSONString];
NSDictionary *jsonObject = [dataModel toJSONObject];
...
Burrows Wang
  • 249
  • 1
  • 7
0

What i do for my objects is i have a method called "toDict" that return a nsdictionary. IN this method i set all attributes i need/want into the dictionary for example

[user setObject:self.first_name forKey:@"first_name"];
[user setObject:self.last_name forKey:@"last_name"];
[user setObject:self.email forKey:@"email"];
Travis Delly
  • 1,194
  • 2
  • 11
  • 20