Refactoring my code for asynchronous NSURLConnection - iphone

There are problems with using synchronous requests. The problem is that I am not really sure how to refactor the code below to use an asynchronous request to accomplish the following two tasks:
Use a UIActivityIndicatorView subview to notify of active fetching;
Implement a Reachability check before the connection request to ensure that there is an Internet connection and that the host is available, i.e. reachabilityWithHostName:#"wwww.mywebhostingisterrible.com".
Currently I have a Fetcher class with a +(Fetcher *)sharedFetcher singleton that is used in all of my view controllers to fetch data. Currently all data is fetched using the following code:
- (NSString *)stringWithUrl:(NSURL *)url {
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
NSData *urlData;
NSURLResponse *response;
NSError *error;
urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
return [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
}
A method that fetches looks like this:
-(NSArray *)fetchDogFoodListing {
NSString *urlString = [NSString stringWithFormat:#"%#query/dogFood/%#/%lli/%#/%#",self.connectionUrl,self.queryCriteria.dogFoodName,self.queryCriteria.dogFoodBrandId,self.queryCriteria.dogFoodIngredients,self.queryCriteria.dogFoodBrand];
NSString *json = [self stringWithUrl:[NSURL URLWithString:urlString]];
return [self.factory buildIKDogFoodArrayWithJSON:json];
}
and a call from the UIViewController in -(void)viewDidLoad looks like this:
self.dogFoods = [[IKFetcher sharedFetcher] fetchDogFoodListing];
I have thought about implementing a delegate in this situation but I am very shaky on how delegation ought to work. I'm not even sure which way it should go. Should the Fetcher have a FetcherDelegate that can notify the view controller of when it is done, so the UI can update? Should the view controller have a delegate so that the fetcher can update the view when stuff is done?
I'm sure based on my questions you can see my inexperience with delegation, so I would appreciate any help.

You could do something like this
dispatch_async(queue, ^{
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
NSData *urlData;
NSURLResponse *response;
NSError *error;
urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
//.. do stuff with data here...
}
}
or you could just do the sendSynchronousRequest code inside a dispatch_sync if you want the connection to be synchronous, though you should really should be as asynchronous as possible.

you may want to look at the brilliant framework by Mugunth Kumar:
http://blog.mugunthkumar.com/products/ios-framework-introducing-mknetworkkit
I plan on using this for NSURLConnection in my future projects

Related

NSURLConnection Bug when I run It in background.... how can I fix?

I've this code but I can't understand why I must run this on the main thread.
If I run this in the background It doesn't do the post request. Is it a bug?
How can I solve this problem?
- (void)setRead:(MWFeedItem *)entry
{ [self getToken:YES];
NSString *url=[NSString stringWithFormat:#"https://www.google.com/reader/api/0/edit-tag?a=user/-/state/com.google/read&i=%#&T=%#", entry.identifier, token];
[self postRequestWithURLState:url];
}
- (void)postRequestWithURLState:(NSString *)url
{
NSString *bodyRequest = nil;
NSURL *requestURL = [NSURL URLWithString:url];
NSMutableURLRequest *theRequest = [[NSMutableURLRequest alloc] init];
//NSLog(#"-------------- bodyRequest: %#", bodyRequest);
[theRequest setURL:requestURL];
[theRequest setTimeoutInterval:0.5];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody:[bodyRequest dataUsingEncoding:NSASCIIStringEncoding]];
[self.oauthAuthentication authorizeRequest:theRequest];
[NSURLConnection connectionWithRequest:theRequest delegate:self];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
this is my call:
-(void)segnaLettura:(MWFeedItem *)item{
[reader setRead:item];
}
- (void) segnaread:(MWFeedItem *)item{
[self performSelectorOnMainThread:#selector(segnaLettura:) withObject:item waitUntilDone:NO];
}
In order for an asynchronous NSURLConnection to function, it requires the thread's runloop to be processed. While new threads automatically get a runloop, it is up to you to run it.
You can learn how to do this in the Threading Programming Guide, and I can explain it more, but most of the time this isn't what you want. Most of the time in iOS, background threads should be managed with NSOperation or GCD. Generally, if you're manually spawning a thread on iOS 4+, you're doing it wrong. There are exceptions, but not often.
The first question here should be "why do I even have a background thread for this?"
If you really need a background thread, then the way you're doing segnaread is probably fine.

How can I use NSURLConnection to make connection in background

In one of my previous post someone suggest me to use the
NSURLConnection *conn = [NSURLConnection connectionWithRequest:theRequest delegate:self];
To make connection in a new thread to keep GUI working without freezing during the connection.
But It now I can realize that this doesn't work.
This is the whole method.
- (void)postRequestWithURLState:(NSString *)url
{
NSString *bodyRequest = nil;
NSURL *requestURL = [NSURL URLWithString:url];
NSMutableURLRequest *theRequest = [[NSMutableURLRequest alloc] init];
//NSLog(#"-------------- bodyRequest: %#", bodyRequest);
[theRequest setURL:requestURL];
[theRequest setTimeoutInterval:2.0];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody:[bodyRequest dataUsingEncoding:NSASCIIStringEncoding]];
[self.oauthAuthentication authorizeRequest:theRequest];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:theRequest delegate:self];
self.web = conn;
}
That is part of a class called greader. So I use this method in this mode.
reader = [[greader alloc] init];
[reader setDelegate:self];
Than I call it [reader postRequestWithURLState:url].
But in this way it still freeze my app for some seconds. How can I execute this action without freezing my app for some seconds?
This is strange. I cannot see why this method would freeze your UI.
One simple solution is to call the method in separate thread. Make the reader a property (or pass it to the method below):
-(void)postReaderRequest:(NSURL)url {
[self.reader postRequestWithURLState:url];
}
and then
[self performSelectorInBackground:#selector(postReaderRequest)
withObject:[NSArray arrayWithObject:url]];
If the result is the same, it must have been something else.
Try using NSThread to execute your NSURLConnection

get url after redirect with stringWithContentsOfURL

NSString* HTML = [NSString stringWithContentsOfURL:url usedEncoding:&enc error:&error];
works great, but if there is a redirect I need to know the url of the redirected page.
Any ideas?
Thanks~~
You will probably want to use NSURLConnection and load manually rather than using the stringWithContesOfURL method. Then you can set a URLConnectionDelegate on your connection. When you get redirected, the connection will call this method on your delegate:
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
The request argument provides the URL that you are being redirected to. You can inspect it and do what you want with it. If you want to allow the redirect to continue then you should return it from your delegate's method.
Here you go (synchronous approach):
NSURLResponse *response;
NSError *error;
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:#"URL_STRING"]];
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(%#,response.URL);

How to abort a synchronized URL request in IPhone

I have an API call. It takes more than 2 minute to get a response from the server. how can i abort it manually while it is processing?
Here is my code:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setTimeoutInterval: 600.0];
[request setHTTPMethod:#"GET"];
NSMutableDictionary* headers = [[[NSMutableDictionary alloc] init] autorelease];
[headers setValue:#"application/json" forKey:#"Content-Type"];
[headers setValue:#"application/json" forKey:#"Accept"];
[headers setValue:val forKey:#"Authorization"];
[request setAllHTTPHeaderFields:headers];
NSError *Error;
NSURLResponse *response = [[NSURLResponse alloc] init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&Error];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
how can i abort the request while its processing.
Thanks
You can't. Use asynchronous connections if you want to be able to cancel.
Also, BTW, you have some errors in your code:
NSError *Error;
NSURLResponse *response = [[NSURLResponse alloc] init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&Error];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
For good measure, Error should be initialized to nil.
You are leaking response. Initialize it to nil, and sendSynchronousRequest:returningResponse:error: will fill it in (if the request succeeds, anyway).
The line [[NSURLConnection alloc] initWithRequest:request delegate:self] starts an asynchronous connection and releases it, after you already did a synchronous connection for the same request. And it leaks the NSURLConnection object. Did you even implement the necessary methods for the informal delegate protocol on your self object?
You can't, as the thread is being blocked by your synchronous request.
synchronous load is built on top of the asynchronous loading code made available by the class. The calling thread is blocked while the asynchronous (sic) loading system performs the URL load on a thread spawned specifically for this load request.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html

iPhone development: How to implement HTTPS connection?

I am working on an iPhone project which need to connect to the IIS server over HTTPS or SSL protocol. Can anyone tell me how to implement HTTPS connection in iPhone? Any advice would be appreciate.
Thank you in advance.
Ben Copsey's ASIHTTPRequest framework makes it trivially easy to issue web requests over SSL.
Modifying the site's example slightly:
NSURL *url = [NSURL URLWithString:#"https://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
NSLog (#"%#", response);
}
Just use NSURLConnection with an NSURLRequest pointing to an NUSUL with https protocol, just like that:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://mySecureServer.net"]];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!error) {
//do something with response & data
}
But I suggest you have a look at the documentation of the URL loading system in Cocoa.
Jason don't forget to implement the connection:canAuthenticateAgainsProtectionSpace and connection:didReceiveAuthenticationChallenge to make sure you're handling the challenges for the Server authentication and Client Authentication:
check out this post that will help you with this https://devforums.apple.com/message/143091#143091
You probably don't have a public certificate. Can you access the https resource with firefox/safari/chrome without an error? if not - that's the problem, not your code.