I have a tabbed bar application in which one of the buttons loads the content of a webpage to a UIWebView.
The problem I am facing is that while the connection attempting to fetch the data the tab bar buttons are non responsive until either the page is done loading or connection has failed.
Is there a better way to perform this operation so the user can switch out of that tab if he/she changes their mind for example.
Thanks and here is the code:
- (void)loadThrillsSite
{
[self.webView setDelegate:self];
NSString *urlString = #"https://www.Thrills.in";
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if ([data length] > 0 && error == nil) [self.webView loadRequest:request];
else if (error != nil) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Connection Error!" message:#"Failed to connect to server\nPlease check your internet connection and try again" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
}];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView;
{
[hudImageView removeFromSuperview];
[self.spinner stopAnimating];
[patternView removeFromSuperview];
}
UIWebView's loadRequest method description:
Connects to a given URL by initiating an asynchronous client request.
It already makes a asynchronous call so you do not need to use another block. Just call [self.webView loadRequest:request]; You can handle errors on - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error method.
Other notes: Your url is not working right now and do not do any UI related work like showing an alert view on background thread. Hope it helps.
- (void)loadThrillsSite
{
[self.webView setDelegate:self];
NSString *urlString = #"https://www.Thrills.in";
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView;
{
[hudImageView removeFromSuperview];
[self.spinner stopAnimating];
[patternView removeFromSuperview];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Connection Error!" message:#"Failed to connect to server\nPlease check your internet connection and try again" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
Related
I am able to generate an alert allowing the user to make a call using a UIWebView with this code:
UIWebView *webV= [[UIWebView alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"tel:1834563578"]];
[webV loadRequest:request];
However, when I use UIWebView to make a call, the system presents an alert. I want to know which button index the user selected. I don't know how to retrieve the index of the option the user chooses in the alert.
Just for iOS10+.
You can detect a call in UIWebViewDelegate:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([request.URL.absoluteString hasPrefix:#"tel:"]) {
// make a call
// this method is available in iOS10
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber]
options:nil
completionHandler:^(BOOL success) {
// if success is NO, user tap cancel button, or other
NSLog(#"%d", success);
}];
return NO; // the default view will not show
}
return YES;
}
Set up UIWebView:
UIWebView *webV= [[UIWebView alloc] init];
webV.delegate = self;
NSURLRequest *request = [NSURLRequest requestWithURL: [NSURL URLWithString:#"tel:1834563578"]];
[webV loadRequest: request];
By this, you will know which button tapped depend
on success in completionHandler.
Use The following Code.
UIAlertAction* cameraButton = [UIAlertAction
actionWithTitle:#"Button1"
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
// do somethingg
}];
UIAlertAction *cancelButton = [UIAlertAction
actionWithTitle:#"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
//do nothing
}];
[alert addAction:cameraButton];
[alert addAction:cancelButton];
[self presentViewController:alert animated:YES completion:nil];
I have used URLRequest to fetch a html file from a pc in my wifi network.
My app fetches a html file from my fileserver and the filename is a number which is typed in the app. Also I have given a 20 seconds timeout for the request. How can I detect whether timeout occurred because I have 2 situations,
1. file does not exist
2. connection is slow
In urlrequest, there is a BOOL for error,no description.
Suggest me a method if possible.
My code is below for only urlrequest
-(void)getHtmlContent{
[self.spinner startAnimating];
NSString *str = #"http://192.168.1.250/rec/";
// NSString *str = #"file:///Volumes/xampp/htdocs/";
str = [str stringByAppendingString:numEntered.text];
str = [str stringByAppendingString:#".html"];
NSURL *url=[NSURL URLWithString:str];
//self.htmlContent = nil;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//NSURLRequest *request = [NSURLRequest requestWithURL:url];
request.timeoutInterval = 20.0;
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL *localfile, NSURLResponse *response, NSError *error) {
if(!error){
if([request.URL isEqual:url]){
NSString *content = [NSString stringWithContentsOfURL:localfile encoding: NSUTF8StringEncoding error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
[numEntered setText:#"0"];
text = #"";
[self.spinner stopAnimating];
self.htmlContent = content;
NSString *myHTMLString = self.htmlContent;
if(myHTMLString != nil) {
if([myHTMLString isEqualToString:#"3"]){
UIAlertView *alrt = [[UIAlertView alloc] initWithTitle:#"LogIn Success" message:#"" delegate:self cancelButtonTitle:#"Continue" otherButtonTitles:nil];
self.view.userInteractionEnabled = YES;
[alrt show];
}
else{
UIAlertView *alrt = [[UIAlertView alloc] initWithTitle:#"LogIn Failed. Try again." message:#"User not authenticated" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
self.view.userInteractionEnabled = YES;
[alrt show];
}
}
});
}
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
[self.spinner stopAnimating];
[numEntered setText:#"0"];
text = #"";
UIAlertView *alrt = [[UIAlertView alloc] initWithTitle:#"Requested file does not exist." message:#"Try again." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
self.view.userInteractionEnabled = YES;
[alrt show];
});
}
}];
[task resume];
}
Since I can not comment I am writing as an Answer.
You need to check the error object to see the type of error that occured.
so in your else block you need to check error.localizedDescription to see what has happened, it would usually tell you that the file was not found or if the request timed out. you can even use your alert to show it like changing your else block as follows
else {
dispatch_async(dispatch_get_main_queue(), ^{
[self.spinner stopAnimating];
[numEntered setText:#"0"];
text = #"";
UIAlertView *alrt = [[UIAlertView alloc] initWithTitle : #"Error"
message : error.localizedDescription
delegate : self
cancelButtonTitle : #"Ok"
otherButtonTitles : nil];
self.view.userInteractionEnabled = YES;
[alrt show];
});
}
You must use this delegate method to handle timeout:-
-(void) connection:(NSURLConnection * ) connection didFailWithError:(NSError *)error {
if (error.code == NSURLErrorTimedOut)
// handle error as you want
NSLog(#"Request time out");
}
I am loading one .aspx web form on UIWebView in iPhone and the form is loading successfully. Now the form is having one choose photo button where users can select a photo/image from iPhone gallery and one submit button. After choosing a photo and when I click on submit button on the form it's throwing an error like "request body stream exhausted". I searched in google also but no luck.
Here is the code snippet
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[activity startAnimating];
activity.hidden = NO;
NSURL *url = [NSURL URLWithString:#"http://rest..com:95134/MobileForm.aspx?processName=NewForm"];
theRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60];
[theRequest setHTTPMethod:#"POST"];
[theRequest setValue:#"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:#"Content-Type"];//image/jpeg
[theRequest setValue:#"image/jpeg" forHTTPHeaderField:#"Content-Type"];// "Content-Type" = "text/html; charset=utf-8";
[webView loadRequest:theRequest];
}
#pragma mark
#pragma mark connection Methods
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
{
NSLog(#"got auth challange");
if ([challenge previousFailureCount] == 0) {
_authed = YES;
/* SET YOUR credentials, i'm just hard coding them in, tweak as necessary */
[[challenge sender] useCredential:[NSURLCredential credentialWithUser:#"user" password:#"pass" persistence:NSURLCredentialPersistenceForSession] forAuthenticationChallenge:challenge];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
{
NSLog(#"received response via nsurlconnection %#",response);
/** THIS IS WHERE YOU SET MAKE THE NEW REQUEST TO UIWebView, which will use the new saved auth info **/
[connection cancel];
[webView loadRequest:theRequest];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
activity.hidden =YES;
NSLog(#"err %#", [error localizedDescription]);
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Message" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection;
{
return YES;
}
#pragma mark
#pragma mark webView Methods
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
{
NSLog(#"Did start loading: %# auth:%d", [[request URL] absoluteString], _authed);
if (!_authed) {
_authed = NO;
/* pretty sure i'm leaking here, leave me alone... i just happen to leak sometimes */
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
return NO;
}
return YES;
}
- (void)webViewDidStartLoad:(UIWebView *)webView{
activity.hidden = NO;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{
activity.hidden = YES;
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
activity.hidden = YES;
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Message" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
But I could able to upload an image and submit the form from Safari app on device. Please help me. Thanks in advance.
Here is my question. How do I display an error if my app is unable to load my remote JSON file? I turned my wifi off on my computer and ran the app in the Simulator. It NSLogs the message that should be displayed if there is connection. How can I fix this? Thanks.
Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *jsonStr = #"http://xxx.com/server.php?json=1";
NSURL *jsonURL = [NSURL URLWithString:jsonStr];
// NSData *jsonData = [NSData dataWithContentsOfURL:jsonURL];
// NSError *jsonError = nil;
NSURLRequest *jsonLoaded = [NSURLRequest requestWithURL:jsonURL];
if(!jsonLoaded) {
UIAlertView *alertView = [[UIAlertView alloc] init];
alertView.title = #"Error!";
alertView.message = #"A server with the specified hostname could not be found.\n\nPlease check your internet connection.";
[alertView addButtonWithTitle:#"Ok"];
[alertView show];
[alertView release];
NSLog(#"No connection, JSON not loaded...");
}
else {
NSLog(#"JSON loaded and ready to process...");
}
}
Your code just creates the request. It doesn't actually fetch the data. You need to use NSURLConnection to fetch the data.
There are multiple ways to fetch the data. This example is for iOS 5.0 or higher:
NSOperationQueue *q = [[[NSOperationQueue alloc] init] autorelease];
NSURLRequest *jsonRequest = [NSURLRequest requestWithURL:jsonURL];
[NSURLConnection sendAsynchronousRequest:jsonRequest
queue:q
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// data was received
if (data)
{
NSLog(#"JSON loaded and ready to process...");
// ... process the data
}
// No data received
else
{
NSLog(#"No connection, JSON not loaded...");
// ... display your alert view
}
}];
You have not actually requested anything yet. Read here on how to make requests.
Basically, what you want to do is to implement NSURLConnectionDelegate protocol and override connection:didFailWithError: function to listen for failure event.
I have searched for awhile and tried many things, but I cannot get this error to go away. I have a table that is refreshed by a pull down method. I also use Apple's Reachability to determine internet connectivity. When I run my application WITH internet, and then while the app is running, shut the internet off, my app crashes trying to display a UIAlertView. Although, when I start my app WITHOUT internet and then turn on internet while the app is running and turn it back off, the app does not crash and everything works as it should. Any help would be greatly appreciated.
The error occurs on the [message show] line.
Edited code:
- (void)loadCallList {
NSURL *theURL = [NSURL URLWithString:#"http://www.wccca.com/PITS/"];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
NSLog(#"Reachable");
self.headerHeight = 45.0;
NSData *data = [[NSData alloc] initWithContentsOfURL:theURL];
xpathParser = [[TFHpple alloc] initWithHTMLData:data];
NSArray *elements = [xpathParser searchWithXPathQuery:#"//input[#id='hidXMLID']//#value"];
if (elements.count >= 1) {
TFHppleElement *element = [elements objectAtIndex:0];
TFHppleElement *child = [element.children objectAtIndex:0];
NSString *idValue = [child content];
NSString *idwithxml = [idValue stringByAppendingFormat:#".xml"];
NSString *url = #"http://www.wccca.com/PITS/xml/fire_data_";
NSString *finalurl = [url stringByAppendingString:idwithxml];
xmlParser = [[XMLParser alloc] loadXMLByURL:finalurl];
[callsTableView reloadData];
}
}
else {
NSLog(#"Not Reachable");
self.headerHeight = 0.0;
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"No Internet Connection"
message:#"Please check your internet connection and pull down to refresh."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[message show];
[message release];
}
[pull finishedLoading];
}
I tested the following method using sendAsynchronousRequest:queue:completionHandler: as the method to download data from the URL. It seems to work fine, I can get the else clause to fire, either by messing up the URL or making the timeout interval .1 seconds.
NSURL *theURL = [NSURL URLWithString:#"http://www.wccca.com/PITS/"];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:5];
[NSURLConnection sendAsynchronousRequest:theRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error == nil) {
//do whatever with the data. I converted it to a string for testing purposes.
NSString *text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#",text);
}else{
NSLog(#"%#",error.localizedDescription);
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"No Internet Connection" message:#"Please check your internet connection and pull down to refresh." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[message show];
}
}];
You have two problems:
You shouldn't be using Reachability to determine whether there is an internet connection. Reachability is only useful to determine when an offline connection comes back online. Really. Making the networking calls is sometimes enough to power up the radios and connect so if you try to pre-check whether there is an internet connection the radios will remain off.
The second problem is that no synchronous networking calls can be made on the main thread. This includes Reachability and [NSData dataWithContentsOfURL:xxx]. Make them on a secondary thread using Grand Central Dispatch, NSOperationQueues, NSURLConnections, or NSThreads. Otherwise your application can lock up if the network isn't in good shape and the system watchdog timer will kill your app.