Wednesday, June 16, 2010

 

HttpHelper for all

Well, that's flattering: the lead developer of WordPress for iOS (WordPress is the world's most popular blogging software) just emailed me, saying nice things about my previously-posted HttpHelper class, and asking for permission to use it in their project.

And why stop with them? So I hereby formally release HttpHelper under the Apache License 2.0, for anyone to use. I've made a few tweaks to the class since I last posted it - one bug fix, and some synchronous accessors for use when you're already in a background thread - so here it is in its entirety:

HttpHelper.h


// HttpHelper.h
// Created by Jonathan Evans on 04/09/09.
// Copyright 2009 Jonathan Evans.

#import


@interface HttpHelper : NSObject {
}
+(NSURLRequest *) buildRequestWithPostKeys:(NSArray *) postKeys postValues:(NSArray *) postValues urlString:(NSString *)urlString;
+(BOOL) doPost:(NSURLRequest *)request forCaller:(id)caller onSuccess:(SEL)successSelector onFailure:(SEL)failSelector;
-(BOOL) doHttp:(NSDictionary *)args;

+(NSURLRequestCachePolicy)getCachePolicyFor:(NSString *)urlString;
+(NSURLRequest *)getURLRequestFor:(NSString *)urlString;
+(BOOL) doGet:(NSString *)urlString forCaller:(id)caller onSuccess:(SEL)successSelector onFailure:(SEL)failSelector;
+(NSString *) doSynchronizedGet:(NSString *)urlString;
+(NSData *) doSynchronizedDataGet:(NSString *)urlString;
+(NSString *) doSynchronizedPostTo:(NSString *)urlString withKeys:(NSArray*)postKeys andValues:(NSArray*)postValues;

@end


HttpHelper.m


// HttpHelper.m
// Created by Jonathan Evans on 04/09/09.
// Copyright 2009 Jonathan Evans.
//

#import "HttpHelper.h"


@implementation HttpHelper

static HttpHelper *singleton=nil;

#pragma mark -
#pragma mark Singleton methods

+(HttpHelper *) getInstance {
if (singleton==nil)
singleton = [[[HttpHelper alloc] init] autorelease];
return singleton;
}

+(id)allocWithZone:(NSZone *)zone {
if (singleton == nil) {
singleton = [super allocWithZone:zone];
return singleton;
}
return nil;
}

-(id)copyWithZone:(NSZone *)zone {
return self;
}

-(id)retain {
return self;
}

-(unsigned)retainCount {
return UINT_MAX;
}

-(void)release {
//pass
}

-(id)autorelease {
return self;
}

- (void)dealloc {
[super dealloc];
}

#pragma mark -
#pragma mark Business logic

+(NSURLRequest*) buildRequestWithPostKeys:(NSArray *) postKeys postValues:(NSArray *) postValues urlString:(NSString *)urlString {
NSURL * url = [NSURL URLWithString:urlString];
NSURLRequestCachePolicy policy = NSURLRequestReloadIgnoringCacheData; // we never want a cache of a post response
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:policy timeoutInterval:30.0]; //TODO: extend timeout
[request setHTTPMethod:@"POST"];

NSMutableData *paramData = [NSMutableData dataWithCapacity:8192];

NSMutableString *params=[[NSMutableString alloc] initWithCapacity:1024];
for (int i=0; i<[postValues count]; i++) {
NSObject* valueToPost = [postValues objectAtIndex:i];
if (i>0)
[params appendString:@"&"];
[params appendString:[postKeys objectAtIndex:i]];
[params appendString:@"="];
[params appendString:[NSString stringWithFormat:@"%@",valueToPost]];
}

[paramData appendData:[params dataUsingEncoding:NSUTF8StringEncoding]];

NSString *msgLength = [NSString stringWithFormat:@"%d", [paramData length]];
[request addValue: msgLength forHTTPHeaderField:@"Content-Length"];
[request setHTTPBody: paramData];
[params release];

return request;
}

+(BOOL) doPost:(NSURLRequest *)request forCaller:(id)caller onSuccess:(SEL)onSuccess onFailure:(SEL)onFailure {

NSArray *keys = [NSArray arrayWithObjects:@"request", @"caller", @"onSuccess", @"onFailure", nil];
NSArray *values = [NSArray arrayWithObjects:request, caller,
[NSValue valueWithBytes:&onSuccess objCType:@encode(SEL)],
[NSValue valueWithBytes:&onFailure objCType:@encode(SEL)],
nil];
NSDictionary *args = [NSDictionary dictionaryWithObjects:values forKeys: keys];
NSThread* uploadThread = [[NSThread alloc] initWithTarget:[self getInstance] selector:@selector(doHttp:) object:args];
[uploadThread start];
[uploadThread release];
return TRUE;
}

+(NSURLRequestCachePolicy)getCachePolicyFor:(NSString *)urlString {
//Hived out to a separate method because we might fine-tune this later.
return NSURLRequestUseProtocolCachePolicy;
// return NSURLRequestReloadIgnoringCacheData;
}

+(NSURLRequest *)getURLRequestFor:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequestCachePolicy policy = [self getCachePolicyFor:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:policy timeoutInterval:30.0];
return request;
}

+(BOOL) doGet:(NSString *)urlString forCaller:(id)caller onSuccess:(SEL)onSuccess onFailure:(SEL)onFailure {
NSURLRequest *request = [self getURLRequestFor:urlString];
NSArray *keys = [NSArray arrayWithObjects:@"request", @"caller", @"onSuccess", @"onFailure", nil];
NSArray *values = [NSArray arrayWithObjects:request, caller,
[NSValue valueWithBytes:&onSuccess objCType:@encode(SEL)],
[NSValue valueWithBytes:&onFailure objCType:@encode(SEL)],
nil];
NSDictionary *args = [NSDictionary dictionaryWithObjects:values forKeys: keys];
NSThread* uploadThread = [[NSThread alloc] initWithTarget:[self getInstance] selector:@selector(doHttp:) object:args];
[uploadThread start];
[uploadThread release];
return TRUE;
}

-(BOOL) doHttp:(NSDictionary *)args
{
@synchronized (self) {
//autorelease pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSURLRequest *request = [args objectForKey:@"request"];
NSObject *caller = [args objectForKey:@"caller"];

SEL onSuccess;
[[args objectForKey:@"onSuccess"] getValue:&onSuccess];
SEL onFailure;
[[args objectForKey:@"onFailure"] getValue:&onFailure];

NSError *error=nil;
NSHTTPURLResponse *response=nil;
NSData *returnData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error ];
NSString * responseString = [[[NSString alloc] initWithData: returnData encoding: NSUTF8StringEncoding] autorelease];

NSString *errorString=nil;

if (error)
errorString = [NSString stringWithFormat:@"HTTP error from %@: %@", [request URL], [error localizedDescription]];
else if (response==nil || returnData==nil)
errorString = [NSString stringWithFormat:@"No response from URL %@",[request URL]];
else if (response.statusCode!=200)
errorString = [NSString stringWithFormat:@"Server error from URL %@",[request URL]];

if (errorString && [errorString length]>0) {
NSLog(@"iTravel Error ",errorString);
[caller performSelectorOnMainThread: onFailure withObject:errorString waitUntilDone:NO];
}
else
[caller performSelectorOnMainThread: onSuccess withObject:responseString waitUntilDone:YES];
[pool release];
}
return TRUE;
}

+(NSString *) doSynchronizedGet:(NSString *)urlString {
NSData *returnData = [HttpHelper doSynchronizedDataGet:urlString];
if (!returnData)
return [NSString stringWithFormat: @"Error: No data received from server",urlString];

NSString * responseString = [[[NSString alloc] initWithData: returnData encoding: NSUTF8StringEncoding] autorelease];
return responseString;
}

+(NSData *) doSynchronizedDataGet:(NSString *)urlString {
NSURLRequest *request = [self getURLRequestFor:urlString];
NSHTTPURLResponse *response=nil;
NSError *error=nil;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

NSString *errorString=@"";
if (error)
errorString = [NSString stringWithFormat:@"Error loading page: %@", urlString, [error localizedDescription]];
else if (response==nil || returnData==nil)
errorString = [NSString stringWithFormat:@"Error - No response from URL %@", urlString];
else if (response.statusCode!=200)
errorString = [NSString stringWithFormat:@"Error - HTTP Error %i from URL %@", response.statusCode, urlString];

if ([errorString length]>0)
return [errorString dataUsingEncoding:NSUTF8StringEncoding];

return returnData;
}

+(NSString *) doSynchronizedPostTo:(NSString *)urlString withKeys:(NSArray*)postKeys andValues:(NSArray*)postValues {
NSURLRequest *request = [self buildRequestWithPostKeys:postKeys postValues:postValues urlString:urlString];
NSHTTPURLResponse *response=nil;
NSError *error=nil;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

NSString *errorString=@"";
if (error)
errorString = [NSString stringWithFormat:@"Error - HTTP Error posting to URL %@: %@", urlString, [error localizedDescription]];
else if (response==nil || returnData==nil)
errorString = [NSString stringWithFormat:@"Error - No response from URL %@", urlString];
else if (response.statusCode!=200)
errorString = [NSString stringWithFormat:@"Error - HTTP Error %i from URL %@", response.statusCode, urlString];

if ([errorString length]>0)
return errorString;

NSString * responseString = [[[NSString alloc] initWithData: returnData encoding: NSUTF8StringEncoding] autorelease];

if ([[responseString lowercaseString] hasPrefix:@"error"])
errorString = [NSString stringWithFormat:@"Error message %@ from URL %@",responseString, urlString];
else if ([[responseString lowercaseString] hasPrefix:@"fail"])
errorString = [NSString stringWithFormat:@"Error - Failure message '%@' when posting to URL %@", responseString, urlString];

if ([errorString length]>0)
return errorString;

return nil; //indicates success
}

@end


How To Use It

The three chief asynchronous interface methods are, for a GET -


+(BOOL) doGet:(NSString *)urlString forCaller:(id)caller onSuccess:(SEL)onSuccess onFailure:(SEL)onFailure


and for a POST -


+(NSURLRequest*) buildRequestWithPostKeys:(NSArray *) postKeys postValues:(NSArray *) postValues urlString:(NSString *)urlString

+(BOOL) doPost:(NSURLRequest *)request forCaller:(id)caller onSuccess:(SEL)onSuccess onFailure:(SEL)onFailure {


I'll give you an example of the former first, as it's easier. The call itself is perfectly straightforward:


NSMutableString *urlString = [NSMutableString stringWithCapacity:128];
[urlString appendString:[Util getSearchPageURL]];
[urlString appendString:@"?locale="];
[urlString appendString:[UserSettings getLanguage]];
[urlString appendString:@"&searchTerms="];
[urlString appendString:[searchBar.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[HttpHelper doGet:urlString forCaller:self onSuccess:@selector(parseSearchResults:) onFailure:@selector(searchFailed:)];


Not, however, the two "@selector" arguments. These must be methods on the caller, and they better expect an NSString* and an NSError*, respectively, as arguments. (Or they can take an NSObject* and cast from there, I suppose, but why bother, right?)

Inside HttpHelper we have to wrap the selectors in NSValues to pass them from method to method, which is a bit annoying, but hey, we only have to do it once.

To call a POST, by comparison:

NSArray *postKeys = [NSArray arrayWithObjects:@"title", @"location", @"comments", @"pageUri", @"sectionName", @"sectionNumber", @"listingName", nil];
NSArray *postValues = [NSArray arrayWithObjects:note.title, [note locationString], note.body, note.pageUri, note.sectionName, note.sectionNumber, note.listingName, nil];
NSURLRequest *request = [HttpHelper buildRequestWithPostKeys:postKeys postValues:postValues urlString:[Util getUploadNoteURL]];
[HttpHelper doPost:request forCaller:self onSuccess:@selector(onUploadSuccess) onFailure:@selector(onUploadError:)];


Note that "onUploadSuccess" here doesn't take an argument - I don't care about the web site's response, the fact of success is all that matters. OK, dubious wisdom that, but the example is relevant to show that the selector methods don't actually have to accept arguments.

We launch a new thread every time we call these methods, so we have to be careful lest we run into concurrency problems. So we synchronize the actual HTTP calls in the "doHttp:" method, which is the one place in the app where we actually go out and connect to the big bad scary Internet.

The synchronous methods are simple enough that I don't think they require examples:


+(NSString *) doSynchronizedGet:(NSString *)urlString;
+(NSData *) doSynchronizedDataGet:(NSString *)urlString;
+(NSString *) doSynchronizedPostTo:(NSString *)urlString withKeys:(NSArray*)postKeys andValues:(NSArray*)postValues;


The DataGet is in case you want NSData instead of an NSString - if you're loading an image, for instance.

Comments:
Your site is truly cool and this is an extraordinary moving article and If it's not too much trouble share more like that. Thank You..
Digital Marketing Course in Hyderabad
 
What an incredible message this is. Truly one of the best posts I have ever seen in my life. Wow, keep it up.
AI Courses in Bangalore
 
Thank a lot. You have done excellent job. I enjoyed your blog . Nice efforts
Data Science Certification in Hyderabad
 
Awesome article. I enjoyed reading your articles. this can be really a good scan for me. wanting forward to reading new articles. maintain the nice work!
Data Science Courses in Bangalore

 
Wow, happy to see this awesome post. I hope this think help any newbie for their awesome work and by the way thanks for share this awesomeness, i thought this was a pretty interesting read when it comes to this topic. Thank you..
Artificial Intelligence Course
 
Excellent Blog! I would like to thank you for the efforts you have made in writing this post. Gained lots of knowledge.
Data Analytics Course
 
I need to thank you for this very good read and i have bookmarked to check out new things from your post. Thank you very much for sharing such a useful article and will definitely saved and revisit your site.
Data Science Course
 
I am sure it will help many people. Keep up the good work. It's very compelling and I enjoyed browsing the entire blog.
Business Analytics Course in Bangalore
 
Thanks for the good news! As far as I know, localization is the process where you create support for other languages ​​for your application. Often, you first make an application with an English interface and then localize it into other languages, such as Japanese. The localization process is time consuming, and the steps slowly change as Xcode is updated. The Localizable.strings file is where you add translation data as key / value pairs. Earlier versions of Xcode generated a Localizable.strings file by default, which could be easily copied for other languages. Recent versions of Xcode do not create a Localizable.strings file by default. I learned this information from posts on Instagram in which the authors talk about the localization of applications for the iPhone. I've seen enough posts on this topic there and almost all of them had at least 60 thousand likes! I am sure in order to achieve such indicators, their authors resorted to using the services of https://soclikes.com/buy-instagram-likes to quickly cheat the number of likes.
 
Hello everyone, this site is awesome! I express my gratitude for this opportunity to express my thoughts. I wanted to tell you about one difficulty that I had to face recently and how I solved this problem. Recently I had to register for Linked in order to find a good job, and I was pushed by the fact that it is impossible to write to employers there directly if I have no general contacts with them, and recruiters do not really pay attention to my profile if I have few subscribers. After a little search on the Internet, I found an excellent service that helped me acquire subscribers on linkdin, it worked quickly and reliably, and most importantly, not expensive. I recommend all beginner job seekers to use the services of https://viplikes.net/buy-linkedin-followers in order to quickly increase the number of subscribers.
 
You have completed certain reliable points there. I did some research on the subject and found that almost everyone will agree with your blog.

Data Science Training in Bangalore

 
I have voiced some of the posts on your website now, and I really like your blogging style. I added it to my list of favorite blogging sites and will be back soon ...

Digital Marketing Training in Bangalore
 
I wanted to leave a little comment to support you and wish you the best of luck. We wish you the best of luck in all of your blogging endeavors.

Artificial Intelligence Training in Bangalore
 
You actually make it seem like it's really easy with your acting, but I think it's something I think I would never understand. I find that too complicated and extremely broad. I look forward to your next message. I'll try to figure it out!

Machine Learning Course in Bangalore
 
I want to leave a little comment to support and wish you the best of luck.we wish you the best of luck in all your blogging enedevors.
data science course in jaipur
 
Excellent blog and article. I enjoy looking at your posts. Thanks for sharing on the web. I am hoping the same best work from you in the future as well. Thank you for sharing great blogging with us!
Data Science Training in Hyderabad
Data Science Course in Hyderabad

 
Reading this article was very useful-- particularly for me, as it gave me some more insight into writing tips. I wanted to add that the author did a good job of explaining those points clearly. This is particularly helpful for new entrepreneurs because it shows how important it is to consider how everyone perceives your business from the outside. I'm looking forward reading other articles soon.
AWS Training in Hyderabad
AWS Course in Hyderabad

 
I want to leave a little comment to support and wish you the best of luck.we wish you the best of luck in all your blogging enedevors.
aws training in hyderabad
 
This is a brilliant article, Given such a great amount of data in it, These kind of articles keeps the clients enthusiasm for the site, and continue sharing more ... good karma. ai courses in chennai
 
I am glad to discover this page. I have to thank you for the time I spent on this especially great reading !! I really liked each part and also bookmarked you for new information on your site.
Data Science Course Syllabus
 
Thanks for sharing this informative content.,
Leanpitch provides online training in Agile team facilitation ,everyone can use it wisely.

Agile team facilitation

ICAGILE ATF
 
Thanks for sharing this informative content.,
Leanpitch provides online training in Agile team facilitation ,everyone can use it wisely.

ICP ATF

Agile facilitator
 
Thanks for sharing this informative content.,
Leanpitch provides online training in Agile team facilitation ,everyone can use it wisely.
Team facilitator in Agile

ICP ATF

 
I want to leave a little comment to support and wish you the best of luck.we wish you the best of luck in all your blogging enedevors.
data science course
 
I am glad to discover this page. I have to thank you for the time I spent on this especially great reading !! I really liked each part and also bookmarked you for new information on your site.
Data Science Training in Chennai
 
Informative blog
data analytics courses in hyderabad
 
What an incredible message this is. Truly one of the best posts I have ever seen in my life. Wow, keep it up.
AI Courses in Bangalore
 
I am really enjoying reading your well written articles. I am looking forward to reading new articles. Keep up the good work.
Data Science Courses in Bangalore
 
I feel very grateful that I read this. It is very helpful and very informative and I really learned a lot from it.
Data Analytics Course
 
온라인카지노 Wow, amazing weblog structure! How long have you ever been blogging for? you made running a blog glance easy.

 
바카라사이트 Keep up the amazing works guys I’ve incorporated you guys to blogroll.

 
토토사이트 That is a very good tip particularly to those fresh to the blogosphere.
Short but very accurate information…


 
토토사이트 Shocking learning and I seize the opportunity to bestow this kind of information to my mates and desire they like it they why I do..

 
I am sure it will help many people. Keep up the good work. It's very compelling and I enjoyed browsing the entire blog.
Business Analytics Course in Bangalore
 
I am glad to discover this page. I have to thank you for the time I spent on this especially great reading !! I really liked each part and also bookmarked you for new information on your site.
Data Science Course in Delhi
 
I am glad to discover this page. I have to thank you for the time I spent on this especially great reading !! I really liked each part and also bookmarked you for new information on your site.
Data Science Course in Noida
 
Nice article with valuable information. Thanks for sharing.

AWS Training in Chennai | AWS Training institute in Chennai
 
Very informative Blog! There is so much information here that can help thank you for sharing.
Data Analytics Course in Bangalore
 
Exellent your post. i reaching daily on your blogs. thanks for sharing this informative information.
Buy YouTube Views
Buy YouTube Subscribers
Buy YouTube Live Stream Views
Buy Facebook Live Views
Buy Instagram Reels Views
Buy Instagram Live Views
Buy Instagram Followers
Buy Facebook Views
 
This design is spectacular! You obviously know how to keep a reader entertained. Between your wit and your videos, I was almost moved to start my own blog (well, almost…HaHa!) Wonderful job. I really enjoyed what you had to say, and more than that, how you presented it. Too cool! Feel free to visit my website; 토토사이트


 
Hello, I'm happy to see some great articles on your site. Would you like to come to my site later? My site also has posts, comments and communities similar to yours. Please visit and take a look Feel free to visit my website; 배트맨토토


 
Extremely overall quite fascinating post. I was searching for this sort of data and delighted in perusing this one. Continue posting. A debt of gratitude is in order for sharing.business analytics course in rohtak

 
Hii,
This is great and awsome post for me. i loved to read your blog. it's really-really amazing. thanks for inspired me by your blog.
Buy Online Pure & Natural Essential Oils
Buy Body Massage Essential Oil Online
Buy Hair Essential Oil Online Lowest Price
Buy Skin Essential Oil Online For Men/Women
 
Hii,
This is great and awsome post for me. i loved to read your blog. it's really-really amazing. thanks for inspired me by your blog.CapitalGrocery
Saffola Active Pro Weight Watchers Edible Oil (Pouch)
Aashirvaad Sugar Release Control Atta (5 kg)
Cadbury Dairy Milk Silk Oreo Red Velvet Chocolate - 60 G (60 gm)
Catch Ajwain Seeds
 
This is a great inspiring blog.You have shared really very helpful information thank you.
Data Scientist Course in Jaipur
 
You finished certain solid focuses there. I did a pursuit regarding the matter and discovered almost all people will concur with your blog.

 
Pleasant data, important and incredible structure, as offer great stuff with smart thoughts and ideas, loads of extraordinary data and motivation, the two of which I need, because of offer such an accommodating data here. data analytics course in kanpur
 
Extremely overall quite fascinating post. I was searching for this sort of data and delighted in perusing this one.
Continue posting. A debt of gratitude is in order for sharing.
data science course in kolhapur
 
I really like reading a post that can make people think. Also, thank you for permitting me to comment!|data science training in jodhpur

 
Thank you for sharing this blog. It was so informative and helpful SEO blog.
Buy Facebook Accounts
Buy Linkdin Accounts
Buy Google Reviews
 
360DigiTMG, the top-rated organisation among the most prestigious industries around the world, is an educational destination for those looking to pursue their dreams around the globe. The company is changing careers of many people through constant improvement, 360DigiTMG provides an outstanding learning experience and distinguishes itself from the pack. 360DigiTMG is a prominent global presence by offering world-class training. Its main office is in India and subsidiaries across Malaysia, USA, East Asia, Australia, Uk, Netherlands, and the Middle East.
 
it was a wonderful chance to visit this kind of site and I am happy to know. thank you so much for giving us a chance to have this opportunity.. data science course in mysore
 
Great tips and very easy to understand. This will definitely be very useful for me when I get a chance to start my blog. business analytics course in mysore
 
This article is unique. I am impress to read your post, really good quality.
Buy Facebook Accounts
Buy Linkdin Accounts
Buy Google Reviews
 
Very informative message! There is so much information here that can help any business start a successful social media campaign!
data science training in london


 
From some point on, I am preparing to build my site while browsing various sites. It is now somewhat completed. If you are interested, please come to play with casinosite !!

 
Always get the best suite charges, exclusive resort access, comps for gaming play, and more. You’ll just have 카지노 to activate your on-line account using your Grazie Rewards account number and PIN. By submitting this type, you might be} giving your consent for Crescent School of Gaming and Bartending to contact you regarding our applications and providers.
 

Post a Comment

Subscribe to Post Comments [Atom]





<< Home

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]