NSURLConnection status code for Asynchronous request iOS 6 - cocoa-touch

Currently using sendAsynchronous from NSURLConnection to make post and get requests, but can't get the status code in the response. Most post suggest the use of NSURLConnection and its delegate methods, which I understand are also Asynchronous.
I don't understand how the delegates send information back to the calling method (the method that eventually needs the data). The sendAsynchronous method has a call back that I am using right now.
I'm new to this, thank you for your help.

As you are using sendAsynchronousRequest:queue:completionHandle method, I will try to answer in that context:
[NSURLConnection sendAsynchronousRequest:request
queue:queue
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error) {
// This will get the NSURLResponse into NSHTTPURLResponse format
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
// This will Fetch the status code from NSHTTPURLResponse object
int responseStatusCode = [httpResponse statusCode];
//Just to make sure, it works or not
NSLog(#"Status Code :: %d", responseStatusCode);
}];

I have a wrapper class that makes this very easy and keeps your code clean:
https://github.com/ricardocontrerasrobles/EasyNetwork

Related

How do you get the status code from dataTaskWithURL's NSURLResponse?

I am performing a simple get request with Apple's NSURLSession#dataTaskWithURL method
[[mySession dataTaskWithURL:myUrl completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// fancy code goes here...
}] resume];
If I want to have a condition to do something IF the status code was a success, it appears that I have to cast the NSURLResponse as a NSHTTPURLResponse.....
NSUInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
if (!error && statusCode == 200) {
// even fancier code goes here
} else {
// omg!!!!!!!!!
}
...
But---------- My question is: WHY!?!?!?!?!?!?!?
Why in the world would Apple pass in a response object casted to a type that doesn't know its own status?! The fact that I had to write this code makes me think I am doing something very wrong, and there has to be a better way to know whether it was a 200, 404, or 500...
I was hoping I could just change the completionHandler's block argument types to be a NSHTTPURLResponse, however that appears to be a no go!
Protocol design, if done well, always has an eye on the future.
Though we're only using NSURLSession for HTTP right now, it might be possible in the future to use it for other networking protocols. It wouldn't surprise me if you could use it for FTP at some point, for example.
Using a simple response base class for the completion block/delegate parameter and letting you cast based on what kind of network protocol you know you're using gives NSURLSession flexibility for the future.
If a new networking protocol emerges with different needs—perhaps it doesn't even have an integer status code in its response, say—Apple can just add another subclass of NSURLResponse, and leave everything else the same, including the signature of the completion handler block and all the NSURLSession*Delegate protocols.
If they'd "hard coded" the network protocols and completion handler blocks to use NSHTTPURLResponse, then how would you cleanly add a new network protocol, say FTP, to NSURLSession?
(NB: By "protocol", as opposed to "networking protocol"—I use both terms in this answer—I mean the design of the interfaces of the NSURLSession classes, including their actual protocols and equivalent completion handlers.)
Typecast an instance of NSHTTPURLResponse from the response and use its statusCode method.
[NSURLConnection sendAsynchronousRequest:myRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(#"response status code: %ld", (long)[httpResponse statusCode]);
// do stuff
}];

How to wait till asynchronous request returns data before returning value

I have send asynchronous request to a website using the following code:
NSMutableURLRequest *requestSiteToSendData = [NSMutableURLRequest requestWithURL:[[NSURL alloc]initWithString:#"www.example.com"] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
NSURLConnection *connectionToSiteToSendData = [[NSURLConnection alloc]initWithRequest:requestSiteToSendData delegate:self];
Then I used the following method defined inside NSURLConnectionDelegate to get and parse the data after the data fetching is completed.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
//parse 'data'
NSString *parsedData = [self parseDataWithData:data];
}
And then in the method in which I send the asynchronous request, I return parsedData. But the returning should only happen after the data fetching is completed and hence parsing is done. I know the question arises if that is what I need then why I am not using synchronous request. It is because I don't want my other methods to hang up when the loading is going on in background.
Quick answer : if it's asynchronous, you don't want to wait the asynchronous method.
One of the bests option would be :
The object calling wanting the data should set itself as the object that runs the asynchronous method, and in didReceiveData, you call a method such as updateData:(NSString *)parsedData, which handles the newly received data
The object calling the method should use KVO to observe any change on a property of the object that runs the asynchronous method.
Tell me if you need more informations.
Asynchronous requests run on separate thread, So we don't need to worry about handling view lockup.
If you want send a synchronous request then you have to use GCD to achieve the same. And various other details like, how much data is send/received etc. will not be available in synchronous request.
Synchronous request are helpful if your code next state is dependent on data received in response of the request.
As far as i understand you want that to return data after web call is complete. so i would suggest that create any method for webcall that returns NSData and do something like this:
NSHTTPURLResponse* urlResponse = nil;
NSError *error = [[NSError alloc] init];
NSData *responseData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&urlResponse error:&error];
if ([urlResponse statusCode] >= 200 && [urlResponse statusCode] < 300) {
// return responseData from here.
}
else {
NSLog(#"%d",[urlResponse statusCode]);
NSString *result = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"%#",result);
}
and you don't want to hung up your View. so call this method in background thread. like this:
[self performSelectorInBackground:#selector(WebCallMethod) withObject:nil];
Hope it Helps!!
You have this delegate method which will execute when all the downloading is completed from tha server successfully.Use this method to do the remaining process
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
// receivedData is declared as a method instance elsewhere
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
}
Ok this method gets executed when the all data is recieved.What you should do is to collect all data from -didReceiveData delegate method and then use it to parse in this method.
A must read document for you

iOS5 - Implementing NSURLConnection sendAsynchronousRequest:

I am familiar with using the following method. I know that when using the following, you need to implement at least the required protocol methods:
[NSURLConnection setConnection:[[NSURLConnection alloc] initWithRequest:request delegate:self]];
Can someone explain something that I have yet to been able to get an answer during my research?
What about when using the following asynchronous method call? Are there any required protocol methods that need to be implemented from NSURLConnection?
Thanks
[NSURLConnection sendAsynchronousRequest:request
queue:queue
completionHandler:^(NSURLResponse *response,NSData *data,NSError *error)
{
//Handle response here
});
Looking at the documentation, you don't need to implement any protocol.
This will give you the same result as using sendSynchronousRequest:returningResponse:error: except :
1) your request will be asynchronous
2)Your handler will be executed in the queue you passed.

NSURLConnection sendAsynchronousRequest:queue:completionHandler not working in iOS 4.3

I am using [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) in my app. By using this my app is terminated in iOS 4.3 but it is working fine in iOS 5.0.
How to use this in iOS 4.3 can any one help me.
Here's a full implementation that works for me. Feel free to rename it and add as a category on NSURLConnection, or just add it as a local method in the class you're working in.
-(void)sendAsynchronousRequest:(NSURLRequest*)request queue:(NSOperationQueue*)queue completionHandler:(void(^)(NSURLResponse *response, NSData *data, NSError *error))handler
{
__block NSURLResponse *response = nil;
__block NSError *error = nil;
__block NSData *data = nil;
// Wrap up synchronous request within a block operation
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
}];
// Set completion block
// EDIT: Set completion block, perform on main thread for safety
blockOperation.completionBlock = ^{
// Perform completion on main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
handler(response, data, error);
}];
};
// (or execute completion block on background thread)
// blockOperation.completionBlock = ^{ handler(response, data, error); };
// Execute operation
[queue addOperation:blockOperation];
}
EDIT
I had to modify the method because I was making UIKit calls in my completion block (e.g. updating labels etc). So it's actually a bit safer to call completion block on the main thread. (original version commented out)
The method you are trying to use is only available on iOS 5. For earlier OSes, consider using
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error
and wrapping it into a new thread to achieve async behavior.
Both H2CO3 and Ken Thomases suggestions are right.
In addition, you could take a look at ios4-implementation-of-nsurlconnection-sendasynchronousrequestqueuecompletio.
If you use the main queue as the queue where the completion handler performs, you could use (as Tom suggested) the delegate pattern. To avoid duplicate code, you could use a wrapper on NSURLConnection delegates mechanism.
In the other case, if you want to maintain the async behaviour and you don't want to deal with sync call (as H2CO3 suggested, note that his suggestion is also valid) and the completion handler performs in a different queue, then I suggest you to wrap the async delegate pattern in a NSOperation class. This approach is quite difficult but you can find a good way of do this in Concurrent Operations Demystified (see both the posts).
Hope it helps.

How can I download data from a server in cocoa (not touch)?

Like it's written in the title, How can I download data from a server in my Cocoa Application?
So far I looked for, I found this.
If you're not downloading a lot of things in parallel and you're doing a simple GET request, the easiest way to do it is to dispatch a synchronous request to one of the global queues:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com/"]];
NSURLResponse* response = nil;
NSError* error = nil;
NSData* result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// There will be response data in response now, like the http status code
// etc. You should check this information to make sure you didn't get a 404
// or some other http status error
if( result ) {
// you have a good result, do something with it like create a new object or
// pass it to a method on this object, etc.
dispatch_async(dispatch_get_main_queue(), ^{
[self doSomethingWithResponseData:result];
});
} else {
// You got an error making the connection, so handle it
NSLog(#"Error making connection: %#", error);
}
});
**note: this sample code uses GCD and therefore will only run on Snow Leopard (10.6) or better. If you need to target Leopard or Tiger, you can do the same thing using dispatched thread selectors, but not as in-line.
ASIHTTPRequest works for iPhone and Mac