iOS HTTP request and JSON parsing example

This is a very basic requirement when you are doing mobile apps to get data from a remote server and then either display or save it for future use. There are two things that we need to accomplish, first make an HTTP request from the app and then parse the JSON response. The HTTP request is done using the NSURLConnection object and the JSON parsing is done with the help of NSJSONSerialization class. In this example we have text field where you can input the country code. When the user taps on submit the button in the navigation bar it goes out to the remote server and gets the response in JSON format. Now you can parse the JSON data to see if the country code was valid or not and if valid then display the detail screen with additional information that was part of the response. Click here for Backend Java Servlet code

iOS HTTP request and JSON parsing failure iOS HTTP request and JSON parsing example iOS HTTP request and JSON parsing success

Sample JSON data coming from the remote server

{"success":true,
 "countryInfo":{
  "code":"BRA",
  "name":"Brazil",
  "continent":"South America",
  "region":"South America",
  "lifeExpectancy":62.9,
  "gnp":776739.0
 }
}

Interface file for Country Object - Country.h

#import <Foundation/Foundation.h>

@interface Country : NSObject

@property (nonatomic, copy) NSString *code;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *continent;
@property (nonatomic, copy) NSString *region;
@property (nonatomic, copy) NSNumber *lifeExpectancy;
@property (nonatomic, copy) NSNumber *gnp;


-(id)initWithNSDictionary:(NSDictionary *)countryInfo_;

@end

Implementation file for Country Object - Country.m

#import "Country.h"

@implementation Country

@synthesize code;
@synthesize name;
@synthesize continent;
@synthesize region;
@synthesize gnp;
@synthesize lifeExpectancy;

-(id)initWithNSDictionary:(NSDictionary *)countryInfo_
{
    self = [super init];
    if (self) {
        
        NSDictionary *countryInfo = countryInfo_;
        NSLog(@"Country Info = %@",countryInfo);
        self.code = [countryInfo  valueForKey:@"code"];
        self.name = [countryInfo  valueForKey:@"name"];
        self.continent = [countryInfo  valueForKey:@"continent"];
        self.region = [countryInfo  valueForKey:@"region"];
        self.gnp = [countryInfo  valueForKey:@"gnp"];
        self.lifeExpectancy = [countryInfo  valueForKey:@"lifeExpectancy"];
         
    }
    return self;
}

- (void)dealloc
{
    self.code = nil;
    self.name = nil;
    self.continent = nil;
    self.region = nil;
    self.gnp = nil;
    self.lifeExpectancy = nil;
    
}

@end

Interface file for App Delegate - HttpRequestJSONAppDelegate.h

#import <UIKit/UIKit.h>
#import "InputViewController.h"

@interface HttpRequestJSONAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UINavigationController *navigationController;
@property (strong, nonatomic) InputViewController *inputViewController;

@end

Implementation file for App Delegate - HttpRequestJSONAppDelegate.m

#import "HttpRequestJSONAppDelegate.h"

@implementation HttpRequestJSONAppDelegate

@synthesize navigationController;
@synthesize inputViewController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    //create the navigation controller and add the controllers view to the window
    navigationController = [[UINavigationController alloc] init];
    [self.window addSubview:[self.navigationController view]];
    
    //check if the Input viewcontroller eixsts, otherwise create it
    if(self.inputViewController == nil)
    {
        InputViewController *inputView = [[InputViewController alloc] init];
        self.inputViewController = inputView;
    }
    
    //push the first viewcontroller into the navigation view controller stack
    [self.navigationController pushViewController:self.inputViewController animated:YES];
    
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    //do nothing
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    //do nothing
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    //do nothing
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    //do nothing
}

- (void)applicationWillTerminate:(UIApplication *)application {
    //do nothing
}

@end

Interface file for Root View Controller - InputViewController.h

#import <UIKit/UIKit.h>
#import "DisplayViewController.h"

@interface InputViewController : UIViewController

@property (nonatomic, strong) UILabel *myLabel;
@property (nonatomic, strong) UILabel *myHelpText;
@property (nonatomic, strong) UITextField *countryCode;

@property (strong, nonatomic) DisplayViewController *displayViewController;

@end

Implementation file for Root View Controller - InputViewController.m

#import "InputViewController.h"

@interface InputViewController ()

@end

@implementation InputViewController

@synthesize myLabel;
@synthesize countryCode;
@synthesize displayViewController;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //set the title of the navigation view
    [self.navigationItem setTitle:@"Country Inquiry"];
    
    
    //create a text field for our country code and add to the view
    countryCode = [[UITextField alloc] init];
    [countryCode setBorderStyle: UITextBorderStyleRoundedRect];
    [countryCode setFrame:CGRectMake(10.0f,10.0f,200.0f,30.0f)];
    [countryCode setPlaceholder:@"Enter Country Code here"];
    [countryCode setContentVerticalAlignment: UIControlContentVerticalAlignmentBottom];
    [countryCode setAutocapitalizationType: UITextAutocapitalizationTypeAllCharacters];
    [self.view addSubview: countryCode];
    
    //create a label to display error message
    CGRect myFrame = CGRectMake(10.0f, 50.0f, 250.0f, 40.0f);
    self.myLabel = [[UILabel alloc] initWithFrame:myFrame];
    self.myLabel.font = [UIFont boldSystemFontOfSize:16.0f];
    self.myLabel.textAlignment =  NSTextAlignmentLeft;
    [self.view addSubview:self.myLabel];
    
    //some help text for users
    myFrame.origin.y += 30.0f;
    myFrame.size.height += 100.0f;
    self.myHelpText = [[UILabel alloc] initWithFrame:myFrame];
    self.myHelpText.numberOfLines = 0;
    self.myHelpText.text = @"Some of the valid Country codes are USA, CHN, CAN and BR";
    [self.view addSubview:self.myHelpText];

    
    //create a submit button in the navigation bar
    UIBarButtonItem *myButton = [[UIBarButtonItem alloc]
                                 initWithTitle:@"Submit"
                                 style:UIBarButtonItemStylePlain
                                 target:self
                                 action:@selector(getCountryInfo:)];
    [self.navigationItem setRightBarButtonItem:myButton];
}

- (void) getCountryInfo:(id)sender {
    
    //get reference to the button that requested the action
    UIBarButtonItem *myButton = (UIBarButtonItem *)sender;
    
    //check which button it is, if you have more than one button on the screen
    //you must check before taking necessary action
    if([myButton.title isEqualToString:@"Submit"]){
        NSLog(@"Clicked on the bar button");
        self.myLabel.text = @"";
        
        //string for the URL request
        NSString *myUrlString = @"http://demo.mysamplecode.com/JQuery/CountryInfo";
        //create string for parameters that we need to send in the HTTP POST body
        NSString *body =  [NSString stringWithFormat:@"countryCode=%@", countryCode.text];
        //create a NSURL object from the string data
        NSURL *myUrl = [NSURL URLWithString:myUrlString];
        
        //create a mutable HTTP request
        NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:myUrl];
        //sets the receiver’s timeout interval, in seconds
        [urlRequest setTimeoutInterval:30.0f];
        //sets the receiver’s HTTP request method
        [urlRequest setHTTPMethod:@"POST"];
        //sets the request body of the receiver to the specified data.
        [urlRequest setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
        
        //allocate a new operation queue
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        //Loads the data for a URL request and executes a handler block on an
        //operation queue when the request completes or fails.
        [NSURLConnection
         sendAsynchronousRequest:urlRequest
         queue:queue
         completionHandler:^(NSURLResponse *response,
                             NSData *data,
                             NSError *error) {
             if ([data length] >0 && error == nil){
                 //process the JSON response
                 //use the main queue so that we can interact with the screen
                 dispatch_async(dispatch_get_main_queue(), ^{
                     [self parseResponse:data];
                 });
             }
             else if ([data length] == 0 && error == nil){
                 NSLog(@"Empty Response, not sure why?");  
             }
             else if (error != nil){
                 NSLog(@"Not again, what is the error = %@", error);
             }
         }];
    }
    
}

- (void) parseResponse:(NSData *) data {
 
    NSString *myData = [[NSString alloc] initWithData:data
                                             encoding:NSUTF8StringEncoding];
    NSLog(@"JSON data = %@", myData);
    NSError *error = nil;
    
    //parsing the JSON response 
    id jsonObject = [NSJSONSerialization
                     JSONObjectWithData:data
                     options:NSJSONReadingAllowFragments
                     error:&error];
    if (jsonObject != nil && error == nil){
        NSLog(@"Successfully deserialized...");
        
        //check if the country code was valid
        NSNumber *success = [jsonObject objectForKey:@"success"];
        if([success boolValue] == YES){
            
            //if the second view controller doesn't exists create it
            if(self.displayViewController == nil){
                DisplayViewController *displayView = [[DisplayViewController alloc] init];
                self.displayViewController = displayView;
            }
            
            //set the country object of the second view controller
            [self.displayViewController setJsonObject:[jsonObject objectForKey:@"countryInfo"]];
            
            //tell the navigation controller to push a new view into the stack
            [self.navigationController pushViewController:self.displayViewController animated:YES];
        }
        else {
            self.myLabel.text = @"Country Code is Invalid...";
        }
        
    }
    
}

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

@end

Interface file for Detail View Controller - DisplayViewController.h

#import <UIKit/UIKit.h>

@interface DisplayViewController : UIViewController

@property (nonatomic, strong) id jsonObject;

@property (nonatomic, strong) UILabel *countryCode;
@property (nonatomic, strong) UILabel *name;
@property (nonatomic, strong) UILabel *continent;
@property (nonatomic, strong) UILabel *region;
@property (nonatomic, strong) UILabel *lifeExpectancy;
@property (nonatomic, strong) UILabel *gnp;

@end

Implementation file for Detail View Controller - DisplayViewController.m

#import "DisplayViewController.h"
#import "Country.h"

@interface DisplayViewController ()

@end

@implementation DisplayViewController

@synthesize jsonObject;

@synthesize countryCode;
@synthesize name;
@synthesize continent;
@synthesize region;
@synthesize lifeExpectancy;
@synthesize gnp;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
 //set the title of the navigation view
    [self.navigationItem setTitle:@"Country Detail"];
    
    //bunch of labels for country information
    CGRect myFrame = CGRectMake(10.0f, 10.0f, 250.0f, 30.0f);
    self.countryCode = [[UILabel alloc] initWithFrame:myFrame];
    self.countryCode.font = [UIFont boldSystemFontOfSize:20.0f];
    [self.view addSubview:self.countryCode];
    
    myFrame.origin.y += 25.0f;
    self.name = [[UILabel alloc] initWithFrame:myFrame];
    [self.view addSubview:self.name];
    
    myFrame.origin.y += 25.0f;
    self.continent = [[UILabel alloc] initWithFrame:myFrame];
    [self.view addSubview:self.continent];
    
    myFrame.origin.y += 25.0f;
    self.region = [[UILabel alloc] initWithFrame:myFrame];
    [self.view addSubview:self.region];
    
    myFrame.origin.y += 25.0f;
    self.lifeExpectancy = [[UILabel alloc] initWithFrame:myFrame];
    [self.view addSubview:self.lifeExpectancy];
    
    myFrame.origin.y += 25.0f;
    self.gnp = [[UILabel alloc] initWithFrame:myFrame];
    [self.view addSubview:self.gnp];

}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:YES];
    
    //create country object from dictionary data
    Country *country = [[Country alloc] initWithNSDictionary:jsonObject];
    
    //format decimal data
    NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    [formatter setNumberStyle:NSNumberFormatterDecimalStyle];
    [formatter setMaximumFractionDigits:2];
    [formatter setMinimumFractionDigits:2];
    
    //set the label values from the country object
    self.countryCode.text = [[NSString alloc] initWithFormat:@"Country Code = %@", country.code ];
    self.name.text = [NSString stringWithFormat:@"Name = %@", country.name] ;
    self.continent.text = [NSString stringWithFormat:@"Continent = %@", country.continent] ;
    self.region.text = [NSString stringWithFormat:@"Region = %@", country.region] ;
    self.lifeExpectancy.text = [NSString stringWithFormat:@"Life Expenctancy = %@",
                                [formatter stringFromNumber:country.lifeExpectancy]];
    self.gnp.text = [NSString stringWithFormat:@"GNP = %@",
                                [formatter stringFromNumber:country.gnp]] ;
    
    
}

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

@end

No comments:

Post a Comment

NO JUNK, Please try to keep this clean and related to the topic at hand.
Comments are for users to ask questions, collaborate or improve on existing.