Revisiting Objective-C, REST, and JSON

I get a lot of hits on this site for two posts.

Objective-C REST and JSON

Objective-C Objects from JSON

Both posts touch on using JSON to create Objective-C objects. The first one mostly talks about great Cocoa Libraries you can use to make REST calls and parse JSON results.

Since that time JSON parsing has become a part of iOS. In iOS 5 Apple introduced NSJSONSerialization.

For a presentation on REST and JSON to @NSSLO back in May I created a super simple project that used NSURL, NSMutableURLRequest, NSURLConnection, and NSJSONSerialization to call the iFixIt API.

If you’re interested in grabbing the project, it’s available on GitHub.

The Code

Most of the RESTTest project is a boiler plate iOS application. There are a couple places in MasterViewController.m you should pay attention to and we’ll take a look at the iFixItBadges and the iFixItBadge classes.

The Basics

To get the ball rolling we make a call to a private method: getBadges.

- (void)getBadges; {
NSURL *url = [NSURL URLWithString:@"http://www.ifixit.com/api/0.1/badges"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:10];
if (request) {
[request setURL:url];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
}

This method is pretty straight forward and uses three of the four classes we mentioned above; NSURL, NSMutableURLRequest, and NSURLConnection. That’s all it takes to do a simple(REST) HTTP GET call. Yes, it’s sample code, so it’s not complex and is not something you’d find in a shipping application as is. It would need some beefing up and it definitely changes if you’re going to do a POST, or DELETE call, not to mention the lack of authentication. I picked the badges call because it didn’t require authentication.

When we allocate and initialize NSURLConnection it takes off and starts doing the work. Notice we’ve specified self as the delegate, which means NSURLConnection will expect us to have implemented the NSURLConnectionDelegate Protocol.

The next method we’ll want to take a look at is connectionDidFinishLoading.

- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
NSString* s = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
NSLog(@"Received data %@", s);

badges = [[IFixItBadges alloc] initWithData:receivedData];

[self.tableView reloadData];
}

This is called by NSURLConnection when it’s finished receiving the response from our badges call. At this point we should have a nice JSON response to parse. Notice we’re working on receivedData, which is private and is built in the didReceiveData method. I’d recommend building the code and running it in the debugger to see how it works.

Back to connectionDidFinishLoading. We have our receivedData (an NSMutableData*), now we’re going to create an IFixItBadges object.

Creating objects from JSON

To review. We’ve called the iFixIt badges method and we’ve received our response data. Now we need to do something with it. Say hello to NSJSONSerialization.

- (id)initWithData:(NSData*)data;
{
if ((self = [super init])) {
badges = [[NSMutableArray alloc] init];

NSError *error = nil;
NSArray *resultData = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
if (resultData && nil == error && badges) {
NSDictionary *badgesData = nil;
NSEnumerator *resultsEnum = [resultData objectEnumerator];
while (badgesData = [resultsEnum nextObject]) {
IFixitBadge *badge = [[IFixitBadge alloc] initWithDictionary:badgesData];
[badges addObject:badge];
}
}
}

return self;
}}

When we get our result back we create an iFixItBadges object, which is a collection of iFixItBadge objects. We could’ve just as easily used NSMutableDictionary or NSMutableArray to hold these objects.

Notice the use of NSJSONSerialization. One call. That’s all it takes to create an array of data we can then iterate over to create an iFixItBadge to add to our collection. Once the collection is created we tell the table view to reload itself using [self.tableView reloadData];

That’s it in a nutshell. If you have any questions about this, or find a problem, please feel free to leave a comment or send email to rob.fahrni@gmail.com.

Happy coding.