JSON Framework for iPhone (Part 2)

October 20, 2008

Editor’s Note: Due to the popularity of this iPhone JSON series, a new three part tutorial series on working with JSON was published in August 2009. You can find the latest JSON iPhone tutorial series at the links below:

  1. iPhone JSON and Flickr Tutorial – Part 1
  2. iPhone JSON and Flickr Tutorial – Part 2
  3. iPhone JSON and Flickr Tutorial – Part 3

In part 1 we shared with you how to download, install and configure an iPhone project to use a JSON framework developed by sbrautaset. In today’s post I will share with you how to use the framework to download and parse a JSON feed. As you will see it is much easier to deal with JSON within an iPhone application than to have to deal with XML.

JSON is most commonly used as an alternative to XML for RESTful style web services. As such any example that demonstrates anything about JSON must first begin with an example of how to download JSON data.

Let’s begin by creating a method called stringWithUrl: that will download data from a specified URL and return the data as an NSString

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (NSString *)stringWithUrl:(NSURL *)url
{
	NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url
                                                    cachePolicy:NSURLRequestReturnCacheDataElseLoad
                                                    timeoutInterval:30];
    	// Fetch the JSON response
	NSData *urlData;
	NSURLResponse *response;
	NSError *error;
 
	// Make synchronous request
	urlData = [NSURLConnection sendSynchronousRequest:urlRequest
                                        returningResponse:&response
                                                    error:&error];
 
 	// Construct a String around the Data from the response
	return [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
}

Now that we have the ability to download the JSON data as a string we are ready to parse the string into an object we can use. What is wonderful about this particular JSON framework is that it can parse JSON into a collection of NSDictionary and NSArray objects which are amazingly simple to deal with.

Combined with the stringWithUrl: method above, we are now ready to use the JSON framework to create another method that will parse the JSON string into an Object …

1
2
3
4
5
6
7
8
- (id) objectWithUrl:(NSURL *)url
{
	SBJSON *jsonParser = [SBJSON new];
	NSString *jsonString = [self stringWithUrl:url];
 
	// Parse the JSON into an Object
	return [jsonParser objectWithString:jsonString error:NULL];
}

NOTE: The method above returns id because the actual object type can vary between an NSDictionary and an NSArray.

Now let’s put this to use! First, consider a real example of a JSON feed. Here is a sample of what a public feed from Jaiku looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
    "title" : "Jaiku | Latest Public Jaikus",
    "url": "http:\/\/jaiku.com",
    "stream": [
        {
        "id": "47163562",
        "title": "Lol....nope",
        "content": "",
        "icon": "http:\/\/jaiku.com\/images\/icons\/jaiku-sms.gif",
        "url": "http:\/\/vicious00013.jaiku.com\/presence\/47163562",
        "created_at": "2008-10-20T18:22:50 GMT",
        "created_at_relative": "1 minute ago",
        "comments": "0",
        "user":
            {
            "avatar": "http:\/\/jaiku.com\/image\/4\/avatar_52304_t.jpg",
            "first_name": "Ronnie",
            "last_name": "Beckett",
            "nick": "vicious00013",
            "url": "http:\/\/vicious00013.jaiku.com"
            }
        },
        {
        "id": "47163407",
        "title": "Nice, so HP refuses to (or can't) sell us the drive carriers for their servers.",
        "content": "",
        "icon": "",
        "url": "http:\/\/randomfrequency.jaiku.com\/presence\/47163407",
        "created_at": "2008-10-20T18:21:16 GMT",
        "created_at_relative": "3 minutes ago",
        "comments": "3",
        "user":
            {
            "avatar": "http:\/\/jaiku.com\/image\/36\/avatar_47586_t.jpg",
            "first_name": "Vincent",
            "last_name": "Janelle",
            "nick": "randomfrequency",
            "url": "http:\/\/randomfrequency.jaiku.com"
            }
        }   ]
}

Here is an how we would use the above methods to download the public feed from Jaiku and cast it to an NSDictionary

1
2
3
4
5
6
7
- (NSDictionary *) downloadPublicJaikuFeed 
{
	id response = [self objectWithUrl:[NSURL URLWithString:@"http://jaiku.com/feed/json"]];
 
	NSDictionary *feed = (NSDictionary *)response;
	return feed;
}

At this point we have everything we need to query any aspect of the feed. For example here is how you might query the “title” field:

1
2
NSDictionary *feed = [self downloadPublicJaikuFeed];
NSLog(@"Here is the title of the feed: %@", [feed valueForKey:@"title"]);

Notice in the sample Jaiku feed there is a value “stream” that is actually a list of objects. This is an example of how an NSArray is created to contain a list of object in JSON. Although the JSON frameworks creates the array, you will still need to cast it from a generic ‘id’ type into an NSArray before you can use it safely. Here is an example of how we would query the array of objects and handle each object in the array…

1
2
3
4
5
6
7
8
9
10
11
12
NSDictionary *feed = [self downloadPublicJaikuFeed];
 
// get the array of "stream" from the feed and cast to NSArray
NSArray *streams = (NSArray *)[feed valueForKey:@"stream"];
 
// loop over all the stream objects and print their titles
int ndx;
NSDictionary *stream;
for (ndx = 0; ndx < stream.count; ndx++) {
	NSDictionary *stream = (NSDictionary *)[streams objectAtIndex:ndx];
	NSLog(@"This is the title of a stream: %@", [stream valueForKey:@"title"]); 
}

Conclusions

As you can see, working with JSON feeds are much simpler than XML feeds. There is no cumbersome parser you have to create; and getting values from the JSON object is as simple as working with an NSDictionary or NSArray. If only more Web Service APIs used JSON the world would be a better place!

42 comments

Thanks for this post. I was JUST looking for info on how to communicate with my ruby/rails backend. This is perfect.

by Geoff on Oct 21, 2008. Reply #

Thanks for the feedback Geoff! Glad I could help.

by Rodney on Oct 21, 2008. Reply #

yup, thanks for providing those needs with a perfect example easy to understand even for the begineers

by Kalaivanan on Sep 30, 2011. Reply #

Thanks for the great tutorial.

But there is one issue. I am not sure, but I think you create a memory leak with

“return [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];”
and
“SBJSON *jsonParser = [SBJSON new];”

because these objects are not released.

by Lars on Oct 30, 2008. Reply #

Thank you verry much ::)

by Pierre Bertram on Dec 11, 2008. Reply #

An awesome tutorial, for sure. Thanks Rodney.

by John on Dec 11, 2008. Reply #

Thank you for this post. I needed it :)

by Pierre on Dec 11, 2008. Reply #

I’m trying to use the Json Framework and I’m getting this when I compile after setting the following options up:

>Copy the content of the ‘SDKs’ folder to ~/Library/SDKs. (You may have
>to create that directory.)

>To make use of this SDK, select your target in the left-hand menu and
>click the blue Info button (Apple-i). Add the following new line to
>the “Additional SDKs” option: “$HOME/Library/SDKs/JSON/$(PLATFORM_NAME).sdk”.
>Finally you have to add the entry ‘-ObjC -ljson’ to the “Other Linker
>Flags” option.

error: There is no SDK with specified name or path ‘/Users/mini/Library/SDKs/JSON/macosx.sdk’

Is there something I didn’t wrong?

by Pete on Dec 12, 2008. Reply #

Great article and thanks for the tutorial, just a side note, the last code snippet has an error. Rather than:

for (ndx = 0; ndx < stream.count; ndx++)

the ‘stream’, should be ‘streams’.

for (ndx = 0; ndx < streams.count; ndx++)

by Pete on Dec 12, 2008. Reply #

@Pete

There are only the four steps outline in part one that you need to follow. I’ve just now repeated the steps in a new project to verify and it continues to work for me. Are you sure you didn’t leave out any of the steps? Here is a quick recap …

1. Download the DMG http://json-framework.googlecode.com/files/JSON_2.1.1.dmg
2. Mount the DMG and copy the directory /Volumes/JSON_2.1.1/SDKs/JSON to ~/Library/SDKs/JSON
3. Now, in the build properties (for both Debug and Release) there are two additional properties to configure (omit the double quotes bellow) …
3.a “Additional SDKs” must be set to “$HOME/Library/SDKs/JSON/$(PLATFORM_NAME).sdk”
3.b “Other Linker Flags” must be set to “-ObjC -ljson”
4. In the source file that uses the JSON library, add the following import “#import <JSON/JSON.h>”

That should do the trick.

by Rodney on Dec 12, 2008. Reply #

I can’t seem to get it to work with the instructions in the INSTALL file on the DMG or with yours, but if I fall back on my Cocoa experience I can drag the libjson.a file into my project IDE and also drag the SBJSON.h, NSObject+SBJSON.h, NSString+SBJSON.h in my project and import the files via a “” local import verses a system import. Everything links and works. Is there some special project setting that is used for .sdk bundles? My .sdks actually look like folders not some bundle icon which hides the internal structure from casual users. Is that correct? Or is there a special chmod setting that needs to be set for these .sdks?

#import “SBJSON.h”
#import “NSObject+SBJSON.h”
#import “NSString+SBJSON.h”

by Pete on Dec 12, 2008. Reply #

Thanks for this post… Helped me alot!

by Brad Parks on Jan 31, 2009. Reply #

ya great

by aravind on Jul 30, 2012. Reply #

it was really nice tutorial. In my case I have a sub object under the main object. how do I access sub objects or sub arrays after I get every ting from the server on my NSDictionary?

tanks

by nex on Feb 11, 2009. Reply #

@nex Getting another JSON object is simple. Use the key to get the object from the NSDictionary and then cast it into a NSDictionary … this is also the method for getting at NSArrray values.

by Rodney on Feb 12, 2009. Reply #

Great article!
The NSDictionary *stream; before the for loop gives warning.I guess it is not required.

by Smriti on Mar 26, 2009. Reply #

Thanks Pete
your instruction worked for. i was unable to configure JSON on my MAC mini running 10.5.6 and iphone OS 2.2.1 but when just drag JSON folder and libjson.a in my project it works fine.

Thanks

by kanyal on May 14, 2009. Reply #

I have spent a lot time to complile the code.
Reason was uninitialized variables ‘response’ and ‘error’

NSURLResponse *response;
NSError *error;

// Make synchronous request
urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];

Better to to the initialized:

NSURLResponse **response = nil;
NSError **error = nil;

Thanks for article!

Mikhail.

by Mikhail on Jul 4, 2009. Reply #

Did you do error checking, especially looking for single quotes in names, ie John O’Connor?

Dave

by David Orchard on Jul 20, 2009. Reply #

Great tutoral! Thanks. Do I need to make a NSMutableData *response global to hold the response. I’m getting null for [feed valueForKey:@"title"] using the Jaiku example output. Thanks.

by Brian on Jul 21, 2009. Reply #

Does anyone know if this counts as using a 3rd party API/framework which may mean it is rejected by the iphone app store?

by Chris on Jul 22, 2009. Reply #

@Chris,

Use of this API will not result in rejection. I have used it within my own application that was accepted and put into the store.

- Rodney

by Rodney on Jul 22, 2009. Reply #

Still a good article for starting out.

One questions I am working with: how to send a JSON string to the URL, for example using an RPC type call to my php files on the server.

John

by John on Aug 9, 2009. Reply #

Hello

It’s ok to deserialize to a dictionary.

But what about to deserialize as objects?

For example I have a book class both in server-side and iphone-side

I want to deserialize the serialized book object of server side to a book object in iphone?

Is it possible?

by balkan on Aug 31, 2009. Reply #

Am I wrong, or shouldn’t you be autoreleasing the return value of stringWithUrl:url (first code fragment) to avoid a memory leak??

Oh another commenter (Lars) noticed the same thing. I think you do need to autorelease.

Haven’t compiled this, but something like:

NSString *ret = [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
return([ret autorelease]);

See p.168 of _Learn Objective-C on the Mac_.

by Mike on Sep 18, 2009. Reply #

Great post, thanks!
I am also trying to figure out how to send (POST) JSON data to a RESTful web service. I did not find a possibility to configure the HTTP method for the NSURLRequest object.

Any idea?

Thanks
Guido

by Guido on Sep 20, 2009. Reply #

Forget my last post. Found the answer here: http://stackoverflow.com/questions/330060/problem-using-nsurlrequest-to-post-data-to-server.

Guido

by Guido on Sep 20, 2009. Reply #

Hey, just figured I’d mention it in case people aren’t HTML savvy – your [code] tag, or whatever formats your code is parsing ampersands, angle brackets, etc as their html elements. &amp, etc.

by Random Developer on Oct 21, 2009. Reply #

Thank you.This article is helpful alot for me.

by balaji on May 5, 2010. Reply #

Thanks for making the tutorial, I really want to understand it properly, but I’m coming up with errors straight away.

The new version of JSON is 2.3, and this requires #import “JSON.h”, not #import <JSON/JSON.h, I figured that out!
After simply copying your code and trying to compile to test, I get the error message SBJSON not declared, there's no class SBJSON, just NSObject+SBJSON. In the installation instructions for the new SBJSON2.3 it doesn't say anything about changing the build properties, do i still need to do this?

I changed SBJSON to SBJsonParser, but now it's saying amp is undeclared, where am I meant to declare amp, and what is it??

any help appreciated!

Mike

by mike on Sep 22, 2010. Reply #

Mike,

Try this:

SBJsonParser *parser = [[SBJsonParser new] autorelease];
NSDictionary *results = [parser objectWithString:jsonString error:nil];
NSLog(@”%@”, results);

Tbone

by tbone1 on Oct 1, 2010. Reply #

Though you don’t know me, you now have my eternal gratitude for this wonderful article.
Bless you.
Much Obliged.

by Arsalan on Oct 2, 2010. Reply #

Im working on a similar project. Im using NSURLConnection to POST data to a php file which i know works because ive tested it with an html POST form manually.

Im having the iOS app post this code:

+ (NSArray *)fetchTimelineForUDID:(NSString *)udid{

NSData *postData = [udid dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSLog(@”%@”,postData);
NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.santiapps.com/iGlobe/readtags2.php"]];
[request setURL:url];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];
NSURLResponse *response;
NSError *error;
NSData *urlData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
return nil;
}

at the moment i return nil just to test out NSLogs….but the thing is the NSURLConnection returns NSData. What im expected to return from this function is an NSArray. How can i make that conversion if thats what needs to be done?

by mars on Oct 2, 2010. Reply #

ok, does that url passed to the stringWithUrl method have to be in the format

GET
http://www……/read.php?var1=value [so u can fetch records where id=value]

or can it be

POST
http://www…./read.php [where the data is in the HTTPbody?]

I cant get the 2nd one to work.

by mars on Oct 2, 2010. Reply #

thanks you ,,,this tou is very good !!!!

by twister on Oct 12, 2010. Reply #

Thanks for the nice tutorial!
A wonderful one…

by Mehdi on Nov 15, 2010. Reply #

Thanks for a very good tutorial, it helped me a lot !
Initially even I was getting the same error that “Mike” was getting.
I hadn’t read the entire article…(I mean the replys and all)

But with my programming experience I learned that instead of creating an SBJSON,
one needs to crate SBJsonParser ‘s object.
As SBJsonParser ‘s objects would respond to / call the parser method !!

by Enigmatic on May 11, 2011. Reply #

Thanks for the tutorial. Wanted to create a simple app to absorb a feed and this should do the trick

by james Verado on Jun 28, 2011. Reply #

Thank you thank you! i was so stuck on my 2nd level of json. your for loop fixed my problem. thanks man!

by jason on Sep 28, 2011. Reply #

Really was a good post and help a lot….

by Vishal Gaikawd on Nov 10, 2011. Reply #

Thanks for your valuable tutorial.i think anyone can understand this JSON Concept clearly and easily.It helped me a lot.

by Jayaprakash Subbarayalu on Nov 30, 2011. Reply #

I am new in Objective C and Frameworks. This tutorial helps me a lot to understand JSON Framework.

Thank You.

by vaishali on Nov 9, 2012. Reply #

Leave a Comment