Top of the page
Close

This is a red error

This is a red error

This is a red error

How to parse JSON files on iPhone in Objective-C into NSArray and NSDictionary

Ondrej Rafaj on 2009.12.16 18:45:02

Hi, today I want to show you how to parse JSON files into the NSArray and NSDictionary and how to use those files and objects. This article should be a really good starting point for you guys who already knows the basics of work with Interface Builder and XCode.

In this project we will be using very useful set of libraries from the json-framework project which is an open-source project available for free on the internet.

Please download source files for JSON framework library project here:

http://code.google.com/p/json-framework/

or you can download and open the example projech available on this page and copy those source files from this project. Files are located Classes/JSON/ folder in this example.

Don't even try to use the framework which is located in the original project on Google Code as any thirdparty framework is not permitted on iPhone platform.

Ok, let's assume you've created a new for example Navigation or Window based project, and you have the neccessary libraries already included in it. Try to build the project (you can use the Cmd + B shortcut) to see that everything is allright and we can move on to the more interesting part.

Now you have to declare IBOutlet for your textview (UITextView) and your buttons (UIButton) IBAction that will carry all the functionality after pressing the button.

IBOutlet UITextView *logWindow;

And

// our text field window
@property (nonatomic, retain) IBOutlet UITextView *logWindow;

// action we'll use after pressing the button to start parsing the file
- (IBAction)startParser:(UIButton *)sender;

the entire source code for your controller's header file (.h) is here:

//
//  TutorialProjectViewController.h
//  TutorialProject
//
//  Created by Ondrej Rafaj on 5.8.09.
//  Copyright Home 2009. All rights reserved.
//

#import 
#import "SBJSON.h"

@interface TutorialProjectViewController : UIViewController {
	
	// ------ Tutorial code starts here ------
	
	// our text field window
	IBOutlet UITextView *logWindow;
	
	// ------ Tutorial code ends here ------
	
	
}

// ------ Tutorial code starts here ------

// our text field window
@property (nonatomic, retain) IBOutlet UITextView *logWindow;

// action we'll use after pressing the button to start parsing the file
- (IBAction)startParser:(UIButton *)sender;

// ------ Tutorial code ends here ------

// This function is for button which takes you to the xprogress.com website
- (IBAction) runXprogressComButton: (id) sender;

@end

Now we have to edit the .m file. First synthesize the logWindow variable:

@synthesize logWindow;

and than, don't forget to release this variable in the dealloc function:

[logWindow release];

Start the IBAction for your button which is called startParser:

- (IBAction)startParser:(UIButton *)sender {
	
}

And start coding :)

You have to find your file in the application bundle (I'll show you how to load this file properly from the internet next time, today you have to inlude the json file into your resources folder), I assume that the json file is called data.json. We will be using just some random jsom file I found on the internet, content looks like that:

{
    "menu": {
        "header": "xProgress SVG Viewer",
        "items": [
            {
                "id": "Open"
            },
            {
                "id": "OpenNew",
                "label": "Open New"
            },
            null,
            {
                "id": "ZoomIn",
                "label": "Zoom In"
            },
            {
                "id": "ZoomOut",
                "label": "Zoom Out"
            },
            {
                "id": "OriginalView",
                "label": "Original View"
            },
            null,
            {
                "id": "Quality"
            },
            {
                "id": "Pause"
            },
            {
                "id": "Mute"
            },
            null,
            {
                "id": "Find",
                "label": "Find..."
            },
            {
                "id": "FindAgain",
                "label": "Find Again"
            },
            {
                "id": "Copy"
            },
            {
                "id": "CopyAgain",
                "label": "Copy Again"
            },
            {
                "id": "CopySVG",
                "label": "Copy SVG"
            },
            {
                "id": "ViewSVG",
                "label": "View SVG"
            },
            {
                "id": "ViewSource",
                "label": "View Source"
            },
            {
                "id": "SaveAs",
                "label": "Save As"
            },
            null,
            {
                "id": "Help"
            },
            {
                "id": "About",
                "label": "About xProgress CVG Viewer..."
            } 
        ]
    }
}

You can create new file by right-clicking the Resources folder and selecting Add -> New file -> Other (Under Mac OS X) -> Empty file. The XML equivalent will look like that:

<menu>
    <header> xProgress Viewer</header>
    <item action="Open" id="Open">Open</item>
    <item action="OpenNew" id="OpenNew">Open New</item>
    <separator/>
    <item action="ZoomIn" id="ZoomIn">Zoom In</item>
    <item action="ZoomOut" id="ZoomOut">Zoom Out</item>
    <item action="OriginalView" id="OriginalView">Original View</item>
    <separator/>
    <item action="Quality" id="Quality">Quality</item>
    <item action="Pause" id="Pause">Pause</item>
    <item action="Mute" id="Mute">Mute</item>
    <separator/>
    <item action="Find" id="Find">Find...</item>
    <item action="FindAgain" id="FindAgain">Find Again</item>
    <item action="Copy" id="Copy">Copy</item>
    <item action="CopyAgain" id="CopyAgain">Copy Again</item>
    <item action="CopySVG" id="CopySVG">Copy SVG</item>
    <item action="ViewSVG" id="ViewSVG">View SVG</item>
    <item action="ViewSource" id="ViewSource">View Source</item>
    <item action="SaveAs" id="SaveAs">Save As</item>
    <separator/>
    <item action="Help" id="Help">Help</item>
    <item action="About" id="About">About xProgress Viewer...</item>
</menu>

Ok, now we are going to get the path to the file data.json:

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"data" ofType:@"json"];

Than you have to load contents of this file:

NSString *fileContent = [[NSString alloc] initWithContentsOfFile:filePath];

Allocate new instance of your json parser:

SBJSON *parser = [[SBJSON alloc] init];

And parse the first level of the file:

NSDictionary *data = (NSDictionary *) [parser objectWithString:fileContent error:nil];

// getting the data from inside of "menu"
NSDictionary *menu = (NSDictionary *) [data objectForKey:@"menu"];

NSDictionary is something like an array, which has numeric keys but you can use for example strings as a key.

This new NSDictionary is taken from the data dictionary by selecting the only key on this level, which is menu [data objectForKey:@"menu"].

Now we can get some more data , like the content of header as a string (NSString):

NSString *header = (NSString *) [menu objectForKey:@"header"];

And an array that is in the json file enclosed into the square brackets.

NSArray *items = (NSArray *) [menu objectForKey:@"items"];

Now you want to go trough the array and do something with the data init. You can do something like that:

for (id *item in items) {
		
		// if the item is NSDictionary (in this case ... different json file will probably have a different class)
		NSLog(@"One item: %@", [NSString stringWithFormat:@"Item -> %@", (NSDictionary *) item]);
		
}

On the end of the function don't forget to release the json data parser:

[parser release];

This file in the example is slightly different as I've used a separated function to add results into the UITextView we've created earlier.

This function is not doing anything else than adding new records on the top of the logWindow:

- (void)addRowToLogWindow:(id)data {
	
	logWindow.text = [NSString stringWithFormat:@"Adding data: %@

%@", data, logWindow.text]; // adding new row + 2x new line "
"
	
}

Code for the entire .m file is here:

//
//  TutorialProjectViewController.m
//  TutorialProject
//
//  Created by Ondrej Rafaj on 5.8.09.
//  Copyright Home 2009. All rights reserved.
//

#import "TutorialProjectViewController.h"

@implementation TutorialProjectViewController

// ------ Tutorial code starts here ------

@synthesize logWindow;


// function for adding an 
- (void)addRowToLogWindow:(id)data {
	
	logWindow.text = [NSString stringWithFormat:@"Adding data: %@

%@", data, logWindow.text]; // adding new row + 2x new line "
"
	
}

- (IBAction)startParser:(UIButton *)sender {
	
	// getting path to the file
	NSString *filePath = [[NSBundle mainBundle] pathForResource:@"data" ofType:@"json"];
	
	NSLog(@"Path: %@", filePath);
		
	// reading content of the file, don't use the [NSString stringWithContentsOfFile:@"/Your/Filepath/"]; as this is deprecated since iPhone SDK 3.0
	NSString *fileContent = [[NSString alloc] initWithContentsOfFile:filePath];
	
	//NSLog(@"File content: %@", fileContent);
	
	// creating new parser
	SBJSON *parser = [[SBJSON alloc] init];
	
	// parsing the first level
	NSDictionary *data = (NSDictionary *) [parser objectWithString:fileContent error:nil];
	
	// getting the data from inside of "menu"
	NSDictionary *menu = (NSDictionary *) [data objectForKey:@"menu"];
	
	// getting the first value which is stored in the header
	NSString *header = (NSString *) [menu objectForKey:@"header"];
	[self addRowToLogWindow:[NSString stringWithFormat:@"Header -> %@", header]];
	
	// parsing all the items in to the NSArray
	NSArray *items = (NSArray *) [menu objectForKey:@"items"];
	
	// reading all the items in the array one by one
	for (id *item in items) {
		
		// if the item is NSDictionary (in this case ... different json file will probably have a different class)
		[self addRowToLogWindow:[NSString stringWithFormat:@"Item -> %@", (NSDictionary *) item]];
		
	}
	for (id *item in items) {
		
		// if the item is NSDictionary (in this case ... different json file will probably have a different class)
		NSLog(@"One item: %@", [NSString stringWithFormat:@"Item -> %@", (NSDictionary *) item]);
		
	}
	
	// releasing parser
	[parser release];
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
	
	// removing the default data from our UITextView
	logWindow.text = @"";
	
    [super viewDidLoad];
	
}



// ------ Tutorial code ends here ------


/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        // Custom initialization
    }
    return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/





/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/

- (void)didReceiveMemoryWarning {
	// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
	
	// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
	// Release any retained subviews of the main view.
	// e.g. self.myOutlet = nil;
}

// This function is for button which takes you to the xprogress.com website
- (IBAction) runXprogressComButton: (id) sender {
	NSURL *url = [[[NSURL alloc] initWithString: @"http://www.xprogress.com/"] autorelease];
	[[UIApplication sharedApplication] openURL:url];
}


- (void)dealloc {
    
	// ------ Tutorial code starts here ------
	
	[logWindow release];
	
	// ------ Tutorial code ends here ------
	
	[super dealloc];
}

@end

Now you have to connect your button and textview in Interface Builder to the IBAction for the button and logWindow outlet to the UITextView.

Now you can try to run the application and see if the data are parsed properly into the logWindow.

Hope that everything works for you. If not, feel free to leave me a comment under this article and I'll try to answer promptly. If you have any problems with the code on this website please do not use the contact form on this page as your question may be useful to someone else as well.

Thanks for your time, follow us on twitter (http://twitter.com/xprogresscom/) and come back soon for another tutorial :))

See u soon,

Ondrej

Ondrej Rafaj

Ondrej Rafaj

Senior Software Archiect @ ondrej-rafaj.co.uk

I am available to give you a free quote or start working on your project ... just give me a call or drop a line. Find all my detail on my portfolio site ondrej-rafaj.co.uk

Back to top Comment

Comments ... Why not to get involved!
  • tommy huang

    tommy huang

    from 221.181.**.** @   

    iphone engineer

  • Ondrej

    Ondrej

    from 88.101.**.** @   

    goot to know tommy?! :)

Comment

Leave a Reply


Back to top

IE SUCKS, DON'T USE IT :) Digg this page