Load HTML NSString into a UIWebView - iphone

Im doing a project where I connect to a webpage using the NSURLConnection to be able to monitor the status codes that are returned (200 OK / 404 ERROR). I would like to send the user to the top url www.domain.com if I recieve 404 as status code and if i recieve as 200 status code I would like to load the page in to a webview. I have seen several implementations of this problem by creating a new request but I feel that it is unnecessary since you already received the html in the first request so i would just like to load that HTML in to the webView.
So i try to use the [webView loadHTMLFromString: baseURL:] but it doesn't always work, I have noticed that when i print the NSString with html in the connectionDidFinnishLoading it sometimes is null and when I monitor these cases by printing the html in didReceiveData a random number of the last packets is NULL (differs between 2-10). It is always the same webpages that doesn't get loaded. If I load them to my webView using [webView loadRequest:myRequest] it always works. My implementation looks like this perhaps someone of you can see what Im doing wrong.
I create my first request with a button click.
-(IBAction)buttonClick:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://www.domain.com/page2/apa.html"];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url]
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if( theConnection )
{
webData = [[NSMutableData data] retain];
}
else
{
}
}
Then I monitor the response code in the didReceiveResponse method by casting the request to a NSHTTPURLResponse to be able to access the status codes and then setting a Bool depending on the status code.
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
if ([ne statusCode] == 200) {
ok = TRUE;
}
[webData setLength: 0];
}
I then check the bools value in connectionDidFinnishLoading. If I log the html NSString I get the source of the webpage so i know that it isn't an empty string.
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *html = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:#"http://www.domain.com/"];
if (ok) {
[webView loadHTMLString:html baseURL:url];
ok = FALSE;
}
else {
// Create a new request to www.domain.com
}
}
webData is an instance variable and I load it in didReceiveData like this.
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data];
}

I am assuming that webData is an instance variable on your class. I think your problem is that you are not setting webData to the data you are getting from the NSURLConnection. Try something like this:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[webData appendData:data];
}
If that doesn't do the trick try adding an NSLog() after the NSString *html = [[NSString alloc]... line, like so:
NSLog(#"HTML: %#", html);
That will tell you whether you are getting HTML or not and whether the problem is with your NSURLConnection code or your UIWebView IBOutlet.

You are mixing two ways of performing connection - synchronous and asynchronous too. If the asynchronous finishes before the synchronous, you reinitialize webData to empty string. So even if synchronous populated webData it would be cleared.
// you create asynchronous connection which starts downloading in background immediately
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
// you create another synchronous connection which will block until the URL is downloaded
[NSURLConnection sendSynchronousRequest:theRequest returningResponse: &responseHeader error: nil];
// assuming your theRequest is valid, theConnection is always non-nil, so this is always TRUE
if (theConnection) {
// you reset content of webData, so if your synchronous connection has downloaded something, you throw it away here
webData = [[NSMutableData data] retain];
} else ...
Try to remove unnecessary/buggy call to sendSynchronousRequest:returningResponse:error: and it might work.
Anyway - where do you populate webData with data ? You did implement connection:didReceiveData: and append what comes into webData, right ? If you didn't - well, that's the problem you are seeing.

Related

'for' loop crashes when downloading from NSMutableArray

I have 4 elements in my NSMutableArray. I have this neat code for downloading files and displaying the file's data in UITextView for testing purposes. Without the for loop, everything is fine. The code that gives me the problem is in this function:
- (void)complexDownload {
int i;
for (i=0; i < downloadArray.count; i++) {
if (isBusy == NO) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
downloadURL = [downloadArray objectAtIndex:i];
NSLog(#"URL is %#", downloadURL);
NSLog(#"Downloading object at index %i", i);
NSURL *url = downloadURL;
NSURLRequest *theRequest=[NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSURLConnection *theConnection = [NSURLConnection connectionWithRequest:theRequest delegate:self];
if (theConnection) {
self.downloadData = [NSMutableData data];
isBusy = YES;
NSLog(#"Busy value in download cycle equals %i, downloading", isBusy);
} else {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"Connection failed");
isBusy = NO;
}
}
}
}
I first thought that the problem might be in the isBusy BOOL, but even without the if condition the app crashes. The compiler gives me no error but this one:
Here's the link for the big screenshot.
The rest of the functions are as follows:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[downloadData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *dataString = [[NSString alloc] initWithData:downloadData encoding:NSASCIIStringEncoding];
self.dataTextView.text = dataString;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"Download finished!");
isBusy = NO;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"%#", error);
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
All the NSLogged values are more than fine, the Array has got links and all the links are correct.
My guess is that at some point either downloadArray[i] is corrupt at some point, or it's not an NSUrl. The code crashes in CFURLCopyAbsoluteURL() called from [NSURLRequest requestWithURL...].
You take the async api initWithRequest:delegate: and try to make it synchronous by using isBusy flag. This approach is very wrong to begin with, the NSURLConnection class is smart enough, do don't need to use arbitrary flags if you use it properly.
You should seriously reconsider using NSOperations or GCD. If you're planning to do more complicated connectivity programming maybe you should consider using a third party framework like RestKit.
I think it's a problem with url-object in [NSURLRequest requestWithURL:url
It is not necessary to copy the URL in an extra object. Try this:
NSLog(#"URL is %#", [downloadArray objectAtIndex:i]);
NSLog(#"Downloading object at index %i", i);
NSURL *url = [downloadArray objectAtIndex:i];
(or add self. before downloadURL)
If your downloadArray contains NSStrings:
NSURL *url = [NSURL URLWithString:[downloadArray objectAtIndex:i]];
I would recommend using external framework like [ASIHTTPRequest](http://allseeing-i.com/ASIHTTPRequest/
Get rid of the for loop and the isBusy indicator.
In complexDownload always process the first or the last (what ever is more suitable) object only and then remove it from the array. In connectionDidFinish invoke complexDownload again. Use performSelector for that. The wait time may even be 0.0f. By doing so your downloadArray would act as some sort of queue.

NSURLConnection distinguish 2 different request

In my app I need to download and post some data...
First of all I need to download some data and then I need to do a post request.
I Use async request to don't freeze the UI of my app...
But when I call my method to post some data... I don't care about data returned from server.
But the this method are called also when I do some post request.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)aResponse
{
NSLog(#"------------------------------- connectionDidReceiveResponse");
expectedResponseLength = [NSNumber numberWithFloat:[aResponse expectedContentLength]];
URLresponse = aResponse;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.responseData appendData:data];
}
How can I do my post request like this below without calling (automatic) this 2 methods (up) (used when I download info) and without freezing user GUI (I don't care data when I do post request but I need data in the 1st case)?
My post request is this:
- (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;
}
I was looking around the internet for a solution, I eventually just created my own subclass of NSURLConnection and assigned a tag variable to distinguish. Check out this blog post for more information
You can hold a reference to each of the different requests after performing them, then make some conditional code in the delegate methods that does something different for the two.
That's a rudimentary solution and feels like treating symptoms to me. Maybe you should refactor your approach and create controllers for each of the two operations and perform all of network communication there (it seems like you're doing it all in a view controller now) rather than where you're doing it now.

Check if URL-file exist or not

I wonder how I can check if a file exist on a server or not, without downloading the data first.
I have around 30 different objects and some of them is connected to a movie on a server. At the moment I use NSData to control if the the URL exist, and then shows the movie, or if it doesn't and then alerts the user that there is no video for that object. The code I use for the moment:
NSString *fPath = [[NSString alloc] initWithFormat:#"http://www.myserver/%#", [rows idNr]];
NSURL *videoURL = [NSURL URLWithString:fPath];
NSData *videoData = [NSData dataWithContentsOfURL:videoURL];
url = [NSURL URLWithString:fPath];
[fPath release];
if (videoData) {
[self performSelectorOnMainThread:#selector(playVideo:) withObject:url waitUntilDone:NO];
} else {
NSLog(#"videodata false");
errorLabel.hidden = NO;
activityView.hidden = YES;
}
"rows idNr" is the name of the object. This method is doing what I want, but the problem is that with NSData it first "downloading" the file, and when the URL is validated as a file, the movie is loading once again in the movieplayer. This means that it takes twice as long to load the file.
Suggestions?
It took me a while to dig out my answer to one of the previous questions on this topic. Quote:
You can use a NSMutableURLRequest to send a HTTP HEAD request
(there’s a method called setHTTPMethod). You’ll get the same
response headers as with GET, but you won’t have to download the whole
resource body. And if you want to get the data synchronously, use the
sendSynchronousRequest… method of NSURLConnection.
This way you’ll know if the file exists and won’t download it all if it does.
Make an URLConnecion object with desired url request and add NSURLConnectionDelegate into .h file like I want to check "yoururl" is exist or not then you need to do is
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString: #"http://www.google.com"]];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
and then you can track http status code in delegate function of NSURLConnectionDelegate
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
int code = [(NSHTTPURLResponse *)response statusCode];
if (code == 404)
{
// website not found
// do your stuff according to your need
}
}
You can also find various status code here.
NSError *err;
if ([videoURL checkResourceIsReachableAndReturnError:&err] == NO)
NSLog(#"wops!");
Here's the code for the accepted answer (for your convenience):
How to make call
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"HEAD"];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
You could do this by checking the size of the file via an FTP server, using the SIZE command. If the file size is zero then the file simply do not exist.
Check here on how to do this.
You could of course also do this by using a NSURLRequest with NSURLConnection, checking for the status to be either 200 (success) or 404 (failed). The 404 status doesn't have to be that the file doesn't exist though, it could also be that the file just couldn't be retrieved.

download and save zip file to iphone

i want to download the zip file from web but unable to figure out that how it is possible
i can download image /text/xml file but unable to download a zip file
Can someone guide me how to download zip files from web?
Thanks
If you're using NSURLConnection, it works exactly the same way no matter which type the file has.
Example: (typed off of my head, no guarantee that it works this way and you should obviously implement error checking)
- (void) download
{
self.loadedData = [NSMutableData data]; // make 'loadedData' a property of the class
NSURL *url = [NSURL URLWithString:#"http://..."];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:20.0];
[urlRequest setValue:#"Optional User Agent" forHTTPHeaderField:#"User-Agent"];
// shoot it off
NSURLConnection *mainConnection = [NSURLConnection connectionWithRequest:urlRequest delegate:self];
if (nil == mainConnection) {
NSLog(#"Could not create the NSURLConnection object");
}
}
Then you must handle the incoming data in the delegate methods, e.g. to just save your data:
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[loadedData appendData:data];
}
Take a look at the other delegate methods and implement them, you should deal with authentification challenges and fail responses. You can also for example set:
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
in connection:didReceiveResponse: and set it to NO again in connectionDidFinishLoading:.

How to retrieve a response from server for the request sent?

I am developing an application that connects to a remote web server and exchanges data with the web server frequently. First screen of my application provides login screen that authenticates user.
I am able to authenticate user on the web server by sending a request to the server but unable to get response from the server to display success alert to the user on the iphone. In clear, I am not getting any response.
The server I'm using is developed in Java.
I am using the following to send the request to server.
NSString *post = #"username=";
post = [post stringByAppendingString:username];
post = [post stringByAppendingString:#"&password="];
post = [post stringByAppendingString:password];
NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:#"http://example.com/login.action?"]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
NSURLConnection *conn=[[NSURLConnection alloc] initWithRequest:request delegate:self];
And,
- (void)connectionNSURLConnection *)connection didReceiveDataNSData *)data
{
[receivedData appendData:data];
NSString *ReturnStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"In \"didReceiveData()\" : receivedData = %#",receivedData);
NSLog(#"Return String : %#", ReturnStr);
}
This function is never called.
What should I do to receive response for the request I have sent?
A brief collection of my queries:
Example: Login screen that validates a user in Java server
I am sending request that I am able to see at the console of my server application.
I'm unable to get response for the request.
In which format the response data must be sent?
Would someone provide a clear picture of data exchange between the iPhone application and a Java servlet?
Update
I have implemented these three methods also. But no response from server. Can you guide me the process of developing LOGIN application that communicates with a JAVA server by requests and responses? I am stuck with communicating.
Yeah, my server is receiving request from iphone. I am able to see the request that is sent to the server.
I am not able to understand how the data exchange between iphone application and JAVA server takes place. I'm a newbie to this iphone development.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSString *failureMessage = [NSString stringWithFormat:#"Connection failed: %#", [error description]];
NSLog(failureMessage);
}
Try implementing these three methods as well, you might be getting an error or no response. You can tell by using these methods.
you should verify that the server is actually recieving the request from the iphone.
a simple php script should return something.
<?php
echo print_r($_GET, true);
echo print_r($_POST, true);
?>
create a dummy app that makes a request to the script and displays the response
I'm not sure what authentication you refer to with LOGIN, but if the server requires HTTP Auth, you need to implement the delegate method
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
I am using the following to send the request to server.
The code looks OK, but where is this code and what happens before and after the code you've shown us? Is it in a handler for a button press? Is it in a background thread?
For the asynchronous load you are using to work properly, you need to be on a thread with a default run loop, e.g. the main thread. And this code must return control to the run loop, i.e. must not busy wait doing something else.
Another thing to check is your server - is it in fact sending a response? If you send the same request from a browser, what content length do you get back?
Edit: it may help if you also show the java action handler on the server side. For example, does it send a HTTP redirect if the login is successful? And are you implementing the following delegate method:
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
...and if so, what does that method look like. I'm wondering if you've maybe implemented this method and not got the right logic in there, thus stopped a redirect from happening.
U can do it this way...
-(NSString* )createWebServiveRequest:(NSString *)urlLink{
NSURL *url = [NSURL URLWithString:urlLink];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:60];
NSData *returnData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse: nil error: nil ];
NSString *responseString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
return responseString;
}
call the above method with the NSString containing url.....and capture it in the method call.