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.
Related
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
}];
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
For the iOS app I'm working on, I'm currently writing a singleton class that handles asynchronous requests to a server. Here's an example of one of the methods -
- (void)registerUser:(CBCUserRegistration *)userRegistration delegate:(id)<CBCUserRegistrationDelegate>delegate;
within this method, an NSURLConnection is created and sends an asynchronous request. At this point, i need a way to tie the delegate object to the NSURLConnection, so thats when
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
is called, I know which delegate to inform. Because the requests are asynchronous, there may be more than one request going at any time. My initial though was to use an NSMutableDictionary, setting the NSURLConnection as the key and the delegate as the value, but the keys are copied so thats a no go. Can anyone suggest another way to track this?
Thanks in advance.
Avoid using an NSDictionary for this. Instead take an object-oriented approach:
Write a class MyConnection that implements the required NSURLConnectionDelegate callbacks and has a property/ivar of the id<CBCUserRegistrationDelegate>type. Add a start method to MyConnection that creates an NSURLConnection, assigns itself a delegate of that connection, and starts it. Now you can create an instance of MyConnection for every URL request you do. MyConnection keeps hold of the CBCUserRegistrationDelegate and forwards the result it receives from the NSURLConnection.
However, using delegate here is a bit old-fashioned. Use blocks instead, especially if your project uses ARC. NSURLConnection provides a convenient method to do async requests: [NSURLConnection sendAsynchronousRequest:queue:completionHandler:].
For example:
- (void)registerUser:(CBCUserRegistration *)userRegistration delegate:(id<CBCUserRegistrationDelegate>)delegate
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://mysite.com/register"]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
[delegate processRegistrationResponseData:data];
}];
}
Use a NSNumber set to the address of the NSURLConnection as the key, and then you can set another dictionary as the object of the key. You can give it a name, etc, record the object to notify etc. Just remember to remove it when the NSURLConnection is released.
I have a method getnamefornumbers which call a soap based web service(sudzc generated), which return a some data which i store in array to use.
But problem is that when i call the method it takes its time to execute and code after this method also executing, this result in null array.
what can i do so when this method completes its work then rest of the code executes.
You have to use custom delegates.You should define the protocol and delegate the current class to responsible for the class which performs getnamefornumbers. Once the operation done , you should return to caller class.
Here is the example of protocols http://mobiledevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html
You should use the NSURLConnection delegation methods. In an async environment that's the normal behavior:
You make a call (in an async way)
The application keeps running (after you make the 1. call the program continues with the rest of the instructions)
So you have to two solutions, make it sync, so you will only continue after an answer comes (in your case the array is filled), which I would probably disencourage. Or, you make it async, and use the array when you actually have it.
As for specifics in how to implement this, more details must be provided, in order for me to advise you.
Update 1.0
-(void)requestConnectionToServer{
NSURL *url= [NSURL URLWithString:#"myWebServiceURL"];
NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:url];
self.reference=aReference;
[theRequest setHTTPMethod:#"GET"];
[theRequest setTimeoutInterval:20.0];
[NSURLConnection connectionWithRequest:theRequest delegate:self];
}
#pragma mark NSURLConnectionDelegate Implementation
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"Response:%#",[[NSString alloc] initWithData:webData encoding:NSASCIIStringEncoding]);
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"ERROR with theConenction %#",error);
}
Update 2.0
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
myArray = [MyWebServiceAccess getnamefornumbers];
dispatch_sync(dispatch_get_main_queue(), ^{
[myArray makeSomething];
});
});
I've been working on figuring out how to receive HTTP Headers via a request made with NSURLConnection. Typically a request is made with something as simple as the following:
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:request
delegate:self];
The only way I've personally found in Apple's abundant documentation to receive response headers is via a synchronous call using the following NSURLConnection class method:
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error
Here I can easily reference a response object of type NSURLResponse. The problem here is that I'm not ready to make synchronous requests via a mobile device, especially with a network that has high latency such as EDGE. Is it possible to get similar results with the default, asynchronous behavior of NSURLConnection?
In your connection delegate, add the -connection:didReceiveResponse: method. If you're doing a standard HTTP request, the NSURLResponse object passed in will actually be an NSHTTPURLResponse object, and responds to the -allHeaderFields message. This should be what you're looking for.