Using JSONP with Three20
We use excellent Three20 framework in most of our iPhone projects. One of the great things provided by it is convenient framework for making HTTP requests to web services. There are plugins available to parse both JSON and XML responses. However for one of the projects I needed to parse JSONP response and I haven’t found any ready to use solution.
So I decided to make my own implementation of JSONP response parser, based on available TTURLJSONResponse
class. Here it goes:
@implementation JSONPResponse
// This method is based on the same-named method in TTURLJSONResponse
// Note, that only SBJSON suport is left
- (NSError *) request: (TTURLRequest *) request processResponse: (NSHTTPURLResponse *) response
data: (id) data {
// This response is designed for NSData objects, so if we get anything else it's probably a
// mistake.
TTDASSERT([data isKindOfClass: [NSData class]]);
TTDASSERT(nil == _rootObject);
NSError *err = nil;
if ([data isKindOfClass: [NSData class]]) {
NSString *json = [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease];
// Remove JSONP wrapper
json = [json stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSRange openingBracket = [json rangeOfString: @"("];
NSRange closingBracket = [json rangeOfString: @")" options: NSBackwardsSearch];
if (openingBracket.location != NSNotFound && closingBracket.location != NSNotFound) {
json = [json substringWithRange:
NSMakeRange(openingBracket.location + 1, closingBracket.location - openingBracket.location - 1)];
// Parse JSON
_rootObject = [[json JSONValue] retain];
}
// Report error if failed to parse
if (!_rootObject) {
err = [NSError errorWithDomain: kTTExtJSONErrorDomain
code: kTTExtJSONErrorCodeInvalidJSON
userInfo: nil];
}
}
return err;
}
@end
Full source code is available as Gist: https://gist.github.com/1052330
As you can see, the implementation above is quite dumb – it just extracts JSON content string between parentheses and parses it in a same way as regular JSON response handler.
Response can be done as usual in Three20:
TTURLRequest *request = [TTURLRequest requestWithURL: "http://example.com"
delegate: self];
request.response = [[JSONPResponse new] autorelease];
[request send];
Of course actual delegate methods should also be implemented:
- (void) requestDidFinishLoad: (TTURLRequest *) request {
TTURLJSONResponse *response = request.response;
TTDINFO(@"request succeeded: %@, data = %@", request.response, response.rootObject);
// response.rootObject contains unwrapped JSON data
}
- (void) request: (TTURLRequest *) request didFailLoadWithError: (NSError *) error {
TTDINFO(@"request failed: %@", error);
}
Good luck hacking on your iPhone apps!
Shameless plug
We develop mobile and web apps, you can hire us to work on your next project.