Convert custom iOS object to JSON string

Well if you have done programming in Java you will find that its surprisingly difficult in Objective C to convert your Objects to JSON string. The iOS SDK does provide the NSJSONSerialization class so that you can convert Foundation objects to JSON but it comes with limitations.
An object that may be converted to JSON must have the following properties
  • The top level object is an NSArray or NSDictionary.
  • All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
  • All dictionary keys are instances of NSString.
  • Numbers are not NaN or infinity.
Convert custom iOS object to JSON string  JSON string in iOS TextView

In this example we have an array of custom objects that we would like to represent in JSON string. In order to satisfy the above requirements we have to create toNSDictionary methods in each of our custom objects to get a NSDictionary representation.

Interface file for Country Object - Country.h

#import <Foundation/Foundation.h>

@interface Country : NSObject

@property (nonatomic, strong) NSString *code;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *continent;
@property (nonatomic, strong) NSNumber *population;

-(id)initWithCode:(NSString *)code_
             name:(NSString *)name_
        continent:(NSString *)continent_
       population:(NSNumber *)population_;

- (NSMutableDictionary *)toNSDictionary;

@end

Implementation file for Country Object - Country.m

#import "Country.h"

@implementation Country

@synthesize code;
@synthesize name;
@synthesize continent;
@synthesize population;


-(id)initWithCode:(NSString *)code_
            name:(NSString *)name_
            continent:(NSString *)continent_
            population:(NSNumber *)population_
{
    self = [super init];
    if (self) {
        self.code = code_;
        self.name = name_;
        self.continent = continent_;
        self.population = population_;
    }
    return self;
}

- (NSMutableDictionary *)toNSDictionary
{
    
    NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
    [dictionary setValue:self.code forKey:@"code"];
    [dictionary setValue:self.name forKey:@"name"];
    [dictionary setValue:self.continent forKey:@"continent"];
    [dictionary setValue:self.population forKey:@"population"];
    
    return dictionary;
}

@end

Interface file for Continent Object - Continent.h

#import <Foundation/Foundation.h>
#import "Country.h"

@interface Continent : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSMutableArray *countryList;

- (NSMutableDictionary *)toNSDictionary;

@end

Implementation file for Continent Object - Continent.m

#import "Continent.h"

@implementation Continent

@synthesize name;
@synthesize countryList;

- (NSMutableDictionary *)toNSDictionary
{

    NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
    NSMutableArray *myCountryList = [[NSMutableArray alloc] init];
    for(Country *country in self.countryList){
        [myCountryList addObject:[country toNSDictionary]];
    }
    
    [dictionary setValue:self.name
                  forKey:@"name"];
    [dictionary setValue:myCountryList
                  forKey:@"countryList"];
    
    return dictionary;
}

@end

Interface file for Root View Controller - ConvertToJSONViewController.h

#import <UIKit/UIKit.h>
#import "Country.h"
#import "Continent.h"

@interface ConvertToJSONViewController : UIViewController

@property (nonatomic, strong) NSMutableArray *continentList;
@property (nonatomic, strong) UITextView *myTextView;

@end

Implementation file for Root View Controller - ConvertToJSONViewController.m

#import "ConvertToJSONViewController.h"

@interface ConvertToJSONViewController ()

@end

@implementation ConvertToJSONViewController

@synthesize myTextView;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        
        //intialize our data to be displayed in the table view
        [self loadCountryData];
        
    }
    return self;
}

//create mutable array to hold list of countries that will be displayed
- (void) loadCountryData {
    
    NSMutableArray *array = [[NSMutableArray alloc] init];
    self.continentList = array;
    
    NSMutableArray *countryList = [[NSMutableArray alloc] init];
    Country *country = [[Country alloc] initWithCode:@"USA"
                                                name:@"United States"
                                           continent:@"North America"
                                          population:[[NSNumber alloc] initWithInt:989898]];
    [countryList addObject:country];
    country = [[Country alloc] initWithCode:@"CAN"
                                       name:@"Canada"
                                  continent:@"North America"
                                 population:[[NSNumber alloc] initWithInt:979797]];
    [countryList addObject:country];
    country = [[Country alloc] initWithCode:@"MXN"
                                       name:@"Mexico"
                                  continent:@"North America"
                                 population:[[NSNumber alloc] initWithInt:969696]];
    [countryList addObject:country];
    
    Continent *continent = [[Continent alloc] init];
    continent.name = @"North America";
    continent.countryList = countryList;
    [self.continentList addObject:continent];
    
    countryList = [[NSMutableArray alloc] init];
    country = [[Country alloc] initWithCode:@"CHN"
                                       name:@"China"
                                  continent:@"Asia"
                                 population:[[NSNumber alloc] initWithInt:959595]];
    [countryList addObject:country];
    country = [[Country alloc] initWithCode:@"AFG"
                                       name:@"Afghanistan"
                                  continent:@"Asia"
                                 population:[[NSNumber alloc] initWithInt:939393]];
    [countryList addObject:country];
    
    continent = [[Continent alloc] init];
    continent.name = @"Asia";
    continent.countryList = countryList;
    [self.continentList addObject:continent];
    
 
}


- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.myTextView = [[UITextView alloc] initWithFrame:self.view.bounds];
    self.myTextView.font = [UIFont systemFontOfSize:16.0f];
    [self.view addSubview:self.myTextView];
   
    NSMutableArray *myCountryData = [[NSMutableArray alloc] init];
    for (Continent *continent in self.continentList) {
       [myCountryData addObject:[continent toNSDictionary]];
    }
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization
                        dataWithJSONObject:myCountryData
                        options:NSJSONWritingPrettyPrinted
                        error:&error];
    if ([jsonData length] > 0 &&
        error == nil){
        NSLog(@"Successfully serialized the dictionary into data = %@", jsonData);
        NSString *jsonString = [[NSString alloc] initWithData:jsonData
                                                     encoding:NSUTF8StringEncoding];
        NSLog(@"JSON String = %@", jsonString);
        self.myTextView.text = jsonString;
    }
    else if ([jsonData length] == 0 &&
             error == nil){
        NSLog(@"No data was returned after serialization.");
    }
    else if (error != nil){
        NSLog(@"An error happened = %@", error);
    }
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

Reference