iOS JSON serialization for NSObject-based classes
Asked Answered
T

5

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.

Tinfoil answered 9/5, 2012 at 11:17 Comment(2)
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: #755324 Good luck!Olympiaolympiad
This link helps you.....https://mcmap.net/q/666002/-converting-nsobject-to-nsdictionaryBurbage
M
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.

Many answered 9/5, 2012 at 14:17 Comment(3)
thanks for this, and thanks to Ricard too. I did manage to get a solution built following your initial steer.Tinfoil
Great job! I hope it will not be banned by apple.Hereditament
The library proposed by Malcolm below already does that for you.Unmerciful
P
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]);
Puttyroot answered 27/5, 2013 at 9:37 Comment(1)
An elegant solution. Much appreciated.Kerb
W
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.

Willy answered 29/4, 2013 at 9:49 Comment(0)
A
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];
...
Accretion answered 29/10, 2015 at 3:44 Comment(0)
S
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"];
Skull answered 25/11, 2016 at 4:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.