iPhone SDK: First Steps With JSON Data Using the Twitter API

iPhone SDK: First Steps With JSON Data Using the Twitter API

Tutorial Details
  • Technology: iPhone SDK
  • Difficulty: Beginner - Intermediate
  • Estimated Completion Time: 30 Minutes

Web accessible APIs provide a wealth of resources for extending the functionality of your iPhone apps. These APIs tend to be consumed in two primary data formats: XML and JSON. The iPhone SDK has built-in support for XML parsing, and this will be covered in a separate tutorial. In this tutorial, we will be focusing on adding JSON support to your iOS applications by demonstrating how to create a Twitter reading client app.

JSON Twitter Client Final Preview

Introduction

The JSON Framework is an extremely popular framework. It is used to power a large portion of the commonly used apps on the App Store, including the Facebook app, the Google Maps app, and pretty much every single Twitter client out there.

Why JSON?

There are a couple of reason to chose JSON over XML. The primary reason JSON is preferred is because JSON files are generally smaller in file size than their XML counterparts, and this naturally results in less load time. Another reason worth considering is that Apple’s Push Notification system works best with JSON payloads.

1. Getting Started

Creating an Xcode Project

  1. Create a new Xcode project of your choosing. I’m going to use the View-Based template.
    Creating a new JSON project in Xcode
  2. Download the JSON Framework here.

Adding the Framework

Adding the framework is simple. You just need to drag the files into your project. There is an option to link the library to your project, but that option is now deprecated and not supported.

  1. Drag the JSON folder from the DMG and drop it in your Xcode project. You can add it to the “Other Sources” group if you would like.
  2. Select the ‘Copy items into destination group’s folder’ option when prompted.
    Adding the JSON Framework in Xcode
  3. Add:
    #import "JSON.h"
    

    into the source files where you will be using the framework.

2. Using the JSON Library

A Sample JSON Message

The following is a sample JSON message representing what a person object might look like:

{
         "firstName": "John",
         "lastName": "Smith",
         "age": 25,
         "address": {
             "streetAddress": "21 2nd Street",
             "city": "New York",
             "state": "NY",
             "postalCode": "10021"
         },
         "phoneNumber": [
             { "type": "home", "number": "212 555-1234" },
             { "type": "fax", "number": "646 555-4567" }
         ]
}

Parsing a JSON String

To parse the above, we first load the JSON message into an NSString:

NSString *jsonString = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"data" ofType:@"json"] encoding:NSUTF8StringEncoding error:&error];

From looking at the sample JSON message, we can see that data is encapsulated with both brackets (e.g. [ ] ) and braces (e.g. { } ). The brackets are arrays of data and the braces are the dictionaries of data. As you can see, we are able to nest arrays of dictionaries, and dictionary objects can contain arrays for multiple values.

In the example above, we have a dictionary for contact with keys such as firstname, lastname, etc. The address key points to another dictionary which contains its own key-value pairs. The phoneNumber key in the dictionary contains an array of dictionaries.

To parse an array we use:

NSArray *results = [jsonString JSONValue];

To parse a Dictionary, we use:

NSDictionary *dictionary = [jsonString JSONValue];
NSArray *keys = [dictionary allKeys]; // the keys for your dictionary

Choose the one you need based on your root object. For example, if your API is returning a list of contacts, you would get back an Array of contacts dictionaries. Similarly, if you ask for a twitter timeline, you’re getting back an array of tweets where each tweet is a dictionary.

Creating a JSON String

Creating a JSON string is very simple and straightforward. You create either an NSDictionary with the appropriate Keys and Values or an NSArray with the list of objects. This process is fairly similar to how we parsed the JSON in the previous step.

You would create a dictionary with your data.

NSDictionary *contactData = [NSDictionary dictionaryWithObjectsAndKeys:
								 _titleField.text, @"title",
								 _summaryField.text, @"summary",
								 _urlField.text, @"url",
								 _phoneField.text, @"phone",
								 _bdayField.text, @"birthday",
								 _addrField.text, @"address",
								 nil];

Add your newly created data dictionary to its class

NSDictionary *finalData = [NSDictionary dictionaryWithObject:contactData forKey:@"contact"];

Then generate the JSON Representation of your class dictionary.

NSString *newJSON = [finalData JSONRepresentation];

You can also create your arrays and nest dictionaries or arrays accordingly.

Note: There is no method in the JSON framework that will validate whether a message is valid JSON.

3. Putting It All Together

Let’s create a simple iPhone app that shows a list of the last 5 tweets that contains mobtuts.

We’re going to use the Twitter Search API for simplicity because it doesn’t require authentication or authorization.

A Tweet

The URL for our request is:

http://search.twitter.com/search.json?q=mobtuts&result_type=recent

This will return to us a dictionary result which contains an array of tweets.

To make life a little easier, let’s concentrate on just the user’s profile image url, the tweet text, and the user’s twitter name.

A single resulting tweet looks like this:

{"profile_image_url":"http://a3.twimg.com/profile_images/949941117/zucker_normal.jpg","created_at":"Thu, 10 Jun 2010 03:54:22 +0000","from_user":"mariacarol","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @mobtuts: How to Install Android 2.2 Froyo on iPhone http://bit.ly/c8kBb6","id":15824617764,"from_user_id":311442,"geo":null,"iso_language_code":"en","source":"Seesmic"},{"profile_image_url":"http://a1.twimg.com/profile_images/655595496/retro9_normal.gif","created_at":"Thu, 10 Jun 2010 03:52:28 +0000","from_user":"cead22","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Quiero un #iPhone4 con #FroYo -- How to Install Android 2.2 Froyo on iPhone http://bit.ly/c8kBb6 (@mobtuts)","id":15824510273,"from_user_id":34036310,"geo":null,"iso_language_code":"en","source":"Twitter for BlackBerry\u00ae"},{"profile_image_url":"http://a1.twimg.com/profile_images/769690946/mobiletuts_icon_normal.png","created_at":"Thu, 10 Jun 2010 03:45:51 +0000","from_user":"mobtuts","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Subscribe to the @mobtuts weekly podcast now! Choose RSS http://bit.ly/9LMbGX or iTunes http://bit.ly/bq0QMC","id":15824135971,"from_user_id":104427899,"geo":null,"iso_language_code":"en","source":"HootSuite"},{"profile_image_url":"http://a1.twimg.com/profile_images/63581538/tutsplus_normal.jpg","created_at":"Thu, 10 Jun 2010 03:25:00 +0000","from_user":"tutsplus","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Subscribe to the @mobtuts weekly podcast now! Choose RSS http://bit.ly/9LMbGX or iTunes http://bit.ly/bq0QMC","id":15822900558,"from_user_id":2295627,"geo":null,"iso_language_code":"en","source":"TweetDeck"},{"profile_image_url":"http://a1.twimg.com/profile_images/234225566/illustration_normal.jpg","created_at":"Thu, 10 Jun 2010 03:22:33 +0000","from_user":"GreatTwitTips","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @mobtuts: RT @berryizm_feeds: 5 BlackBerry Theme Developer Tips from MMMOOO a BlackBerry theme and app dev comp... http://bit.ly/agf0ND","id":15822755393,"from_user_id":19637346,"geo":null,"iso_language_code":"en","source":"twitterfeed"}

We can see that we’re looking for the “profile_image_url”, “from_user”, and “text” keys for our app.

The Parser

Let’s create a simple JSON Parser and make the request from the API.

Twitter_SearchAppDelegate.h

#import <UIKit/UIKit.h>
@class Twitter_SearchViewController;
@interface Twitter_SearchAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    NSMutableData *responseData;
    Twitter_SearchViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet Twitter_SearchViewController *viewController;
@end

Now we’ll add the JSON framework to the import statements.

Twitter_SearchAppDelegate.m

#import "JSON.h"

From here, we’ll modify didFinishLaunchingWithOptions method in the App Delegate and make an NSURLRequest to Twitter with the URL to grab the Tweets we want to process. We’ll also set the App Delegate to be the NSURLRequest’s delegate.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    // Add the view controller's view to the window and display.
	responseData = [[NSMutableData data] retain];
	tweets = [NSMutableArray array];
	NSURLRequest *request = [NSURLRequest requestWithURL:
							 [NSURL URLWithString:@"http://search.twitter.com/search.json?q=mobtuts&rpp=5"]];
	[[NSURLConnection alloc] initWithRequest:request delegate:self];
    return YES;
}

Now, since our App Delegate is the NSURLRequest’s delegate, we must implement those delegate methods. We’re primarily interested in being notified when the data is being sent to us and when the request is complete and there is no more data to receive.

#pragma mark NSURLConnection Delegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
	[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
	[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
	label.text = [NSString stringWithFormat:@"Connection failed: %@", [error description]];
}

This is where our parser is doing most of the work. It is parsing the JSON file and creating the array of tweets for us. We get the array and pass it on to the TableViewController to display it.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
	[connection release];
	NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
	[responseData release];
	NSDictionary *results = [responseString JSONValue];
	NSArray *allTweets = [results objectForKey:@"results"];
	[viewController setTweets:allTweets];
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];
}

A Simple TableView

Now we simply use the array we created from the parser to display the data in our TableView.

Twitter_SearchViewController.h

#import 
@interface Twitter_SearchViewController : UITableViewController {
	NSArray *tweets;  // this is the array that was passed to us from the App Delegate
}
@property (nonatomic, retain) NSArray *tweets;
@end

TweetsTableViewController.m

In the controller, we first need to synthesize the property and then set the number of rows that we’ll be displaying

@synthesize tweets;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    return [tweets count];
}

Finally, we’ll display the tweets by referencing their specific keys from the dictionary. From looking at the JSON string earlier, we know we’re looking for the values associated with the “from_user”, “profile_image_url”, and “text” keys.

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }
    // Configure the cell...
	NSDictionary *aTweet = [tweets objectAtIndex:[indexPath row]];
    cell.textLabel.text = [aTweet objectForKey:@"text"];
	cell.textLabel.adjustsFontSizeToFitWidth = YES;
	cell.textLabel.font = [UIFont systemFontOfSize:12];
	cell.textLabel.numberOfLines = 4;
	cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
	cell.detailTextLabel.text = [aTweet objectForKey:@"from_user"];
	NSURL *url = [NSURL URLWithString:[aTweet objectForKey:@"profile_image_url"]];
	NSData *data = [NSData dataWithContentsOfURL:url];
	cell.imageView.image = [UIImage imageWithData:data];
	cell.selectionStyle = UITableViewCellSelectionStyleNone;
    return cell;
}

Additional Considerations

If you’re planning on using either Three20 or httpriot, you do not need to add the JSON framework. Those project already include it in their code. If you’re planning on using ASIHTTPRequest, the JSON framework is not included and you do need to add it yourself.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • Fábio

    Nice and useful tutorial !!! Thanks John!!!

  • http://www.canaydogan.net Can Aydoğan

    Thanks for tuts. Objective-c has too complicated syntax :(

  • http://alnemec.com Al

    Great tutorial! Easy to follow.

    I have just gotten started with iPhone development and have been having a few troubles with NSXMLParser. I look forward to the possibility of a tutorial on that in the future.

  • http://techhui.com Daniel Leuck

    Nicely done John! I’ve always thought JSON was much nicer than XML for this sort of thing. Its so much easier to read.

  • Reinier

    Nice, I was looking for a good tutorial covering JSON in iPhone SDK! However, even with the downloaded source, all I get is a grey screen, although Console tells me 5 tweets were received :(

  • Simon

    I think this tutorial doesn’t meet up to the tutsplus quality. Misspellings, referring wrong classes and too big difference in the steps, everyone can’t “read between the lines”. The only good thing with this one was the JSON converter.

    But I’m still disappointed.

  • http://tudormunteanu.com Tudor

    Wow, the steps are so weird. Good thing the source code helped.

  • http://bogee-games.com Frog

    Good thing – the sources are online. Tutorial itself isn.t descriptive at all. Anyway – Thank you!

  • http://vedovelli.com.br Ved

    Really bad tuto. Shouldn't be here. Please rewrite it!

  • DuMmWiaM

    This tutorial needs re-writing. Many steps are missing, not described at all or poorly explained.

  • http://blog.joshuarussell.com.au Joshua

    Just looking at the Xcode project, why is there a Tweet.h and Tweet.m file? They aren’t being used…

  • http://uvidownloader@gmail.com John doe

    I have a tab bar program that I am working on. In one of my tabs I want to pull tweets from a particular user. I plan to have an announcements tab in my app. So when the user clicks on it it pull all announcements aka tweets. Can anyone help me getting this done ? Newbie. E-mail all comments to uvidownloader@gmail.com.

  • nsocder

    Thanks for going through the trouble of writing this tutorial, but should i suggest that next time instead of posting a tutorial with is merely 10% complete, just provide us with the download link and we will be more than glad to peruse the code ourselves!

  • David

    There were a bunch of errors, but perhaps it’s useful to figure out via reverse engineering?

    In Twitter_SearchViewController.h, cut the final .
    That’s the obvious one. What else is there?

  • Praveen

    Thanks for sharing your code. But how can i identify the url’s if it is in the twitter post?
    Example:

    @mobtuts Thanks for this code.
    http://mobile.tutsplus.com/tutorials/iphone/iphone-json-twitter-api/

    The user must to be able to click the link. Currently, with your code i am not able to view the links in the app. How can i do this?

    • rtorcato

      To detect links. Select the text field and look at the attributes inspector for detection checkboxes. You can enable link detection and some other options (phone numbers, events).

      • Riley

        Oops looks like the demo is using a standard table cell. You can only get link detection in UITextView not UILabel (the default used in tables). You’ll have to customize a table view cell with a UITextView and apply it to your table. Something you should do anyway if you want more flexibility in your cells.

  • http://xyz Dhaval

    Too much step & Declaration missing do it correct….

  • Mike

    Very helpful overall. Thanks!

  • Beau

    I also have a tab bar app and would like to find out how to do this?

  • riyong

    thanks for sharing your code !! thanks

  • resident

    Thanks for this tutorial.

    Anybody knows a similar tutorial with facebook?.

    thanks,

  • neelima

    i am very new to the concept of web services.
    i hav run the code but getting this error
    Command /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.2 failed with exit code 1

    i hav added json framework.

    any help?

  • Michael

    Any idea how to get this done with a Tab Bar Controller? This don’t work for me at all. I can’t find a thing about this with a tab bar, so please help me

  • Rohit

    I am getting only UITableview .nothing else is happening,
    in console also same only starting not reciving any data.
    What changes should i do for getting tweet on iphone.

  • vikas

    I am getting only a blank table view with none of its delegates working,Its not showing data even

  • Nut

    Thank you very much. You solved my JSON !!

  • Bro

    Code is buggy, Please don’t use it until it is being fixed!!

    - Run App
    - Shows Tweet! (Awesome)
    - Press Home button
    - Double click Home button
    - Force quit app
    - Again open app
    - CRASHED!!!!! ( :( )…Keep crashing until you restart your phone!

    Seems like traces of app lingering around in memory after force quit!

  • praveen m

    This is good tutorial for json.

  • kawsar

    How to logout from my twitter account in that iphone application ?

  • http://jonice.web.id Jonice

    Yeah! Thanks for this great article. On forward learning JSON.. :D

  • briomusic

    I am wondering how to use this code in an iOS5 storyboard app.
    In it’s original form this code is launching the viewController from inside the connectionDidFinishLoading-method, by making the viewController subview and calling makeKeyAndVisible.
    However, this is not how a storyboard app is launched, and my resulting problem is that the first viewController is launched before the twitter data has been loaded and parsed.
    Interestingly, the loading is finished in the background which can be verified with NSLog commands, but by that point the viewController has launched and filled its tableview with an empty array.
    Any ideas?

  • vinod

    hello John,
    this code working fine but i have one problem that how could i get json link of my account.

  • Umaid

    Is this tutorial is working with IOS 5 sdk as I am interested in fetching tweets in tableView on IOS 5 sdk and it is not working with me, I have successfully implemented posted and opening tweet Composer on IOS 5 but not looking for fetch all tweets present on my wall. I am looking for a solution , please reply urgent.

  • Mark

    I tried downloading this and running it but it keeps trying to run on MACBOOK … vs iPhone simulator(Xcode 4.2). Do you have any help when trying to grab json encoded data from a website that is using php and putting the data into a table view on iPhone?

  • Dinesh

    Lovely tutorial… a paradise for begineer…. Thanks man..

  • vikas

    nice tutes

  • Sudeep Kumar

    Hello,

    This code is working good. but How to logout from my twitter account in that iphone application ?

  • mahendra

    is this avilable for ios 6.0