Handling the Twitter API in iOS5

Today I’m going to take a bit of a break from writing about Orny to discuss Apple’s APIs for Twitter integration, newly introduced in the iOS 5 SDK.

Specifically, we’re going to cover the Twitter framework (an elaboration of NSHTTPRequest), the Accounts framework (a central framework and daemon for the storage and management of account credentials) and we’ll briefly touch on NSJSONSerialization, Apple’s previously private (and now public) implementation of a JSON-to-Foundation-Object parser (it also works the other way ‘round).

Beginnings

I’m going to assume that you’ve read our previous iOS Tutorials and know how to start a new project. Things are a little different in the new version of Xcode, but not so different that past instructions are too badly out of date. Create a new project, using the following images for clues.

Twitter API iOS 5 Figure 1

Twitter API iOS 5 Figure 2

For those without images we’re using the Single View Application template, adding a Class Prefix of “TWAPIExample”, the Device Family is “Universal” and all three checkboxes are ticked, because we are using Storyboard, Automatic Reference Counting and we want to Include Unit Tests.

Sparse Documentation

At the time of writing, the documentation on some of these Frameworks is still in its early days. I’ve done my best to piece things together from the API documentation and present a coherent overview here. You should, however, definitely review Apple’s documentation before you use any of this code (as it may have changed by the time you read this document).

Forming a Coherent Request

To begin with, we’ll do a simple request to get some results off Twitter’s public Firehose. This does not require authentication. We’re going to grab a single public tweet, and pop it in a UILabel on the screen when the app loads. Nothing fancy.

Adding the Framework

Before we can use the TWRequest class, we need to add the Framework to our project. If you’re not familiar with Frameworks, they’re optional sections of the iOS API that your application can include at compile time. Adding the Framework lets Xcode know that you want to use these features in your app.

Select your project, and scroll down to the Linked Frameworks and Libraries section (under the Summary heading). Click the plus arrow, and scroll down until you find ‘Twitter.framework’. Add it. (At the time of writing, I found the text-input search box at the top of this list failed to work. YMMV; scroll manually if in doubt).

Twitter API iOS 5 Figure 3

Specifying the URL

The first thing we need to do is specify the URL we’re going to hit to grab the data. We’re provided some excellent API documentation, for example the full Twitter REST API Resources list. We’re going to use the REST API for this application. Also on offer is a Twitter Streaming API for high-volume, near-realtime access to voluminous Twitter data, well beyond the scope of what we want to achieve in this example.

Apple’s documentation on TWRequest doesn’t really say what form it expects the URL to take, but as I suspected and discovered experimentally, it wants a full URL to Twitter’s API, plus the path specified in the documentation. In this case, the URL we want is:

https://api.twitter.com/1/statuses/public_timeline.json

Specifying Parameters

The TWRequest object allows us to specify optional parameters, possible values as described in the Twitter API documentation. We’ll encode these as a Foundation Dictionary object (key-value pairs), specifying that we only want a single Tweet to be returned. The code to do so looks like this:

NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:@"1", @"count", nil];

Adding the UILabel Object

In the latest version of Xcode, we now have access to two Storyboards.

The Storyboard replaces the previous panoply of NIB files present in an iOS project. Now all Views appear on the one Storyboard, and are attached to their respective ViewControllers. You can much more easily get a feel for how your application hangs together from the Storyboard, though it can become more cluttered.

Click the Storyboard for your iPhone UI (MainStoryboard_iPhone.storyboard) and select the View. Drag and drop a Label into the center of the View, select the Label, and navigate to its properties. Get through the following three screenshots and we’ll meet at the bottom to change the properties.

Twitter API iOS 5 Figure 4

Twitter API iOS 5 Figure 5

Twitter API iOS 5 Figure 6

Give the View a tag (I’ve used “1’ in this example, just an integer and nothing special). I chose to center-align my text with the Alignment control, and have increased Lines to 5 (allowing the Label to expand to 5 lines rather than truncating text.)

Next, go across to the ‘View Properties’ tab for your Label. You’ll want to resize the Label to be nice and big, so it can display an entire Tweet. Grab the edges and expand it to fill the available space. You’ll also want to make it a multi-line label, so in the field called Lines (see the screenshots, above) increase the number to 3 or 4. Repeat the above steps for your iPad Storyboard ensuring sure to use the same tag!

Creating the TWRequest Object

We’ll add a message, getTweet, to our ViewController object. First, we need to add the Twitter API headers to our ViewController’s header class TWAPIExampleViewController.h around line 10. We’ll specify the functions and methods we need in the header while we’re here, around line 13.

#import <UIKit/UIKit.h>
#import <Twitter/Twitter.h>

@interface TweetAMaticViewController : UIViewController
    @property (nonatomic, retain) UILabel *tweetLabel;

-(void)getTweet;

@end

We’ll use the tweetLabel property as a handle to our UILabel in the View, so we can reference it easily at will. We’ve defined a @property, so of course we need to @synthesize it in TWAPIExampleViewController.m at the start of our implementation:

@implementation TWAPIExampleViewController

@synthesize tweetLabel;

- (void)didReceiveMemoryWarning
{

Now, let’s define the function we’ll use to get the tweet, just before the @end of our implementation in TWAPIExampleViewController.m.

#pragma mark - Twitter Interactions

-(void)getTweet
{
    // Specify the URL and parameters
    NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/1/statuses/public_timeline.json"];   
    NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:@"1", @"count", nil];

    // Create the TweetRequest object
    TWRequest *tweetRequest = [[TWRequest alloc] initWithURL:url parameters:parameters requestMethod:TWRequestMethodGET];    

    [tweetRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
        // Request completed and we have data
        // Output it!

        NSError *jsonError = nil;
        id timelineData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&jsonError];

        if(timelineData == NULL) {
            // There was an error changing the data to a Foundation Object,
            // so we'll output a bunch of debug information.
            NSString *myString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
            NSLog(@"nnConversion to object failed.");
            NSLog(@"HTTP Response code: %d", [urlResponse statusCode]);
            NSLog(@"Output from server: %@", myString);
            NSLog(@"JSON Error: %@nn", [jsonError localizedDescription]);
            abort();
            // TODO: Show a graceful error message here
        }

        NSDictionary *timelineDict = (NSDictionary*) timelineData;
        NSLog(@"nnConversion succeeded!");
        NSLog(@"%@nn", timelineDict);

        self.tweetLabel.text = [[(NSArray*)timelineDict objectAtIndex:0] objectForKey:@"text"];

    }];
}

Whew, busy function! We could probably refactor this substantially by decomposing it and moving much functionality to another class, but for the moment we’ll leave it as-is. Consider this refactoring an exercise for the reader, homework if you will.

NSLog() will output information to the Console, which you can view using Console.App. This is a pretty cheesy way to get information out of your application (you’re much better off getting comfortable with the Debugger) but it’s a simple way to get started and diagnose simple problems (the Debugger sometimes has trouble with large strings and displaying complex data.)

We use a block after performRequestWithHandler to handle the response from the server. A block is the Objective-C 2.0 implementation of a Closure, and explaining them is beyond the scope of this article, but it’s a handy way to encapsulate a simple block of code without having to encase it in a function unto itself (and should be familiar to any Javascript developers in the room).

Finally, we set the text attribute of self.tweetLabel… oh, but we haven’t a handle to that yet, have we?

Handling & Displaying the Response

We need to grab ahold of our Label, and also invoke our getTweet message. We’ll do this in our ViewController’s viewDidLoad message, which defines actions to be taken once the View has been loaded from a NIB file.

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.tweetLabel = (UILabel*)[self.view viewWithTag:1];

    [self getTweet];
}

Remember how we set a tag on our Label in the View earlier? We now use this tag to refer to that View component and take ahold of it, so we can modify it.

Conclusion

If you compile and run the program, it should pull a single Tweet off Twitter’s public Firehose. Who knows where it will be from, or what language it will be in!?

You should now be armed with enough knowledge to display a Tweet via Twitter’s API, including some of its metadata like the author’s screen name and the date and time, it’s just a matter of copying what we did with the label. If you’re feeling especially industrious you could even show a map using location information, if the Tweet includes it…

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://nithin.me Nithin

    Well explained in a simple way! Good one

  • http://www.iridewinnipeg.ca Davo

    Thanks Andy!
    Simple and straightforward. Very nice.
    I can’t wait to go all-the-way-around and set a Tweet from the Objective-C code

    Davo

  • Stevo

    I’ve implemented a similar code base on my app. I’m noticing that it takes a LONG time for the UILabel with the tweet to actually be visible in the iOS Simulator.

    Has anyone else experienced this? Are there any workarounds? I’m currently just showing the user an activity indicator until it finishes. Any help would be much appreciated!

    • Jason

      Yes i am having the same problem.

  • Venkat

    any body having any idea how to Retwitt in iOS 5.0 ,please share with me if any body having ideas about this

    Thanks in advance.

  • angel

    Hi. This is a good tutorial. I find it really useful. Keep it up. Thanks a lot.