I need to check the response status code while loading any of the url in the webview fo. For now we can consider any of the web application I am loading inside the web view.So I need to track down every request withing that webview and check out the response code accordingly. For finding the response code, I need to use NSUrlConnection inside the uiwebview's delegate method "shouldStartLoadWithrequest". Some thing like this -
- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType{
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
if (conn == nil) {
NSLog(#"cannot create connection");
}
return YES;
}
And NSURLConnectionDelegate as --
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(#"connection:didReceiveResponse");
[self log:#"received response."];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
int status = [httpResponse statusCode];
NSLog(#"http status code: %d", status);
if (status == 200) {
NSLog(#"Response OK");
}
else {
NSLog(#"Response is not OK");
}
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
NSLog(#"connection:didReceiveData");
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"connection:didFailWithError - %#", error);
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"connectionDidFinishLoading");
}
But in this process, there are 2 calls on the server. One for the UIWebview and other for the NSUrlConnection. I just need a single call to the server in which I would be able to find the status code. Can anybody please guide me in this ?
I have implemented it using
NSURLProtocol
. For more details, you can check it here - NSURLProtocol
Related
I'm working on login functionality for an app at the moment and I receive a dictionary from the server after connecting. I receive the dictionary in the function
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
which I have in my model. With the dictionary info received from this, I then want to send that dictionary to the view controller, but the function has already returned by the time connectionDidFinishLoading completes.
How can I pass the data back to the view controller?
You need to set teh delegate and implement the callback methods
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:theURL];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self startImmediately:NO];
[urlConnection start];
The delegate methods are
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[_detailsResponse setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_detailsResponse appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Error: %#, %#", [error localizedDescription], [error localizedFailureReason]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Do what you want with the data here.
}
I am using NSURLConnection's sendSynchronousRequest to communicate with server. I wanted to handle authentication which can be achieved using connection delegates but delegates are not called for a synchronous request.
NSData *data = [NSURLConnection sendSynchronousRequest:UrlRequest returningResponse:&response error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
if(!error)
{
// Do something
}
else
{
// Handle error
}
});
However i thought of sending all the request asynchronously using
[NSURLConnection connectionWithRequest:menuRequest delegate:self];
But i have multiple connection in the same class and each connection's success and error are used to perform different task.If i use async request error and success are heard by delegates which are same for all the request in that class, i cannot find out which request failed and which request succeeded. I have two question
If there is a way to implement https for synchronous request.
How to find which connection failed or succeeded among multiple connections in the same class for asynchronous request.
You can achieve this in different ways.
You can put creds in url like https://username:password#domain.tld/api/user.json
You can add add you creds to NSURLCredentialStorage before synchronous connection call.
You can use code below to achieve.
- (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse *__strong*)response error:(NSError *__strong*)error
{
_finishedLoading=NO;
_receivedData=[NSMutableData new];
_error=error;
_response=response;
NSURLConnection*con=[NSURLConnection initWithRequest:request
delegate:self
startImmediately:NO];
[con start];
return _receivedData;
}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
//handle the challenge
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
*_response=response;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
*_error=error;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
}
Anybody knows how to wait the response of a http request? In my code, I am doing a http request to an url and then what i need to do, it is to check the http response in order to decide different treatment. I have something like this:
-(void)check{
[self fetchURL:#"http://something"];
if(response != nil || [response length] != 0){
do something....
}
else{
do something else....
}
}
-(void)fetchURL:(NSString *)urlWeb{
NSURL *url = [NSURL URLWithString:urlWeb];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(#"INSIDE OF didReceiveResponse");
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"INSIDE OF didFailWithError");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"INSIDE OF connectionDidFinishLoading");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
NSLog(#"inside of didReceiveData");
response = [NSString stringWithUTF8String:[data bytes]];
NSLog(#"response: %#", response);
}
I have been trying different options that I have seen around here, but i cant stop the execution of my code and wait for that answer...that means when I check the response of my http request, it always appears empty or with a nil reference...
any help how to figure out??
thanks
You can't evaluate the response value right after your 'fetchUrl' call, because your request is asynchronous, and your code goes on with the execution without waiting for the answer. You will receive the response value only in one of the delegate method, so there's the place where you should check the result.
If you really want to make a synchronous request you can use sendSynchronousRequest:returningResponse:error: like this
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(data){
//use data
}
else{
//check error domain and code
}
(See the Apple NSURLConnection Reference)
But keep in mind that your program will be stuck on this call till it receives a response or goes timeout.
Why don't you write this code:
if(response != nil || [response length] != 0){
do something....
}
else{
do something else....
}
In - (void)connectionDidFinishLoading:(NSURLConnection *)connection; method it wouldn't execute unless you have your complete proper response.
And Just for ado: Right to way to get data properly should be:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[_responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSString *string = [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
if (string)
NSLog(#"string = %#", string);
}
Did you try checking the respons witin connectionDidFinishLoading: ?
That is the very delegate method which is called when the data was transferred successfully. Before that point in time, you should not expect any meaningful data.
Besides - didReceiveData should provide you with portions of data received in the meantime. Apparently you do not seem to process it nor just to store it for later evaluation (witin connectionDidFinishLoading)
I am making a login method on iOS that sends a GET request to a PHP page via url, when I try to read the output from the website, the data is read before the PHP can complete the mysql query, I was wondering if there were any way to wait until the webpage is completely done loading to read the data from it
code:
-(NSString *)getWebpageData:(NSString *)url {
NSURL *URL = [NSURL URLWithString:url];
NSError *error = nil;
NSString *content = [NSString stringWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];
return content;
}
I would try using NSURLConnection via sendAsynchronousRequest like so...
NSOperationQueue *myQueue = [[NSOperationQueue alloc]init];
[NSURLConnection sendAsynchronousRequest:request queue:myQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
//do something
}];
It's mostly self-explanatory that when the handler block is fired you have your content.
Another option would be to invoke the NSURLConnectionDataDelegate. When you call your URL it will fire a few methods to let you know when things are done.
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//Fired on error
}
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
{
//Fired First
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//Fired Second
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//Fired Third
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//Fired Fourth
}
Using the delegate methods you're likely going to want to leverage didReceiveData so that you have your data right there. Good luck.
I'm currently experimenting with the twitter streaming api and i'm trying to get a stream with NSURLConnection. As it doesn't work with twitter, i simplified everything and tried to get some source-code out of google's website, but this doesn't work neither.
The connection starts and ends, but without calling the didReceiveData delegate. I'm sure i'm missing something. Hope you guy's can help me!
In the header: #interface ViewController : UIViewController <NSURLConnectionDataDelegate, NSURLConnectionDelegate, NSURLConnectionDownloadDelegate, NSURLAuthenticationChallengeSender>
And in the body:
- (void)viewDidLoad
{
[super viewDidLoad];
NSURLConnection *connection;
NSMutableURLRequest *request;
// Do any additional setup after loading the view, typically from a nib.
request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.google.com"]];
[request setHTTPMethod:#"GET"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL {
NSLog(#"Stream finished.");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", dataString);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"Connection failed!");
}
A couple of thoughts.
Your declaration of connectionDidFinishLoading doesn't look right. The standard NSURLConnectionDataDelegate method does not have a destinationURL parameter:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"%s", __FUNCTION__);
}
Given the presence of NSURLAuthenticationChallengeSender, if you're expecting a challenge (which you won't get with Google web site) then you'd obviously handle it accordingly:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
// For example, if you have a userid/password to use, see if this is the first
// challenge, and then tell NSURLConnection to try using those credentials, and if
// it failed a second time, you might just cancel the authentication challenge.
if (challenge.previousFailureCount == 0) {
NSURLCredential *credential = [NSURLCredential credentialWithUser:kUserID password:kPassword persistence:NSURLCredentialPersistenceForSession];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
} else {
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}
By the way, you do not want to call start method when you use initWithRequest or connectionWithRequest. It's only needed if you do a simple initWithRequest:delegate:startImmediately: and instruct it to not startImmediately.
Anyway, I used the following and it works fine:
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.google.com"]];
[NSURLConnection connectionWithRequest:request delegate:self];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"%s", __FUNCTION__);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%s: %#", __FUNCTION__, dataString);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"%s error=%#", __FUNCTION__, error);
}
Someone said here that it was their SOAP format
NSURLConnection delegate method: didReceiveData not called ...Why ?? (iPhone SDK)
This also may be what you are looking for
NSURLConnection didReceiveData not called
Your NSURLConnection local variable connection is going out of scope at the end of viewDidLoad. Add a property to your ViewController to hold the NSURLConnection variable in scope.