How to show an alert when the server is not working properly? - iphone

I am getting list using url by doing parsing it using xml parser. sometimes the server is not working properly. then how to give an alert when server is not working properly. I have given the code below
-(NSMutableArray*)getCustomerList:(NSString *)count category:(NSString *)aCategory alphabetic:(NSString *)alphabeticValue favorite:(NSString *)isFavoriteString
{
[self updateStatus];
if (internetConnectionStatus == NotReachable)
{
UIAlertView *reachbleAlert = [[UIAlertView alloc] initWithTitle:#"message"
message: #"No network available alert"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles: nil];
[reachbleAlert show];
[reachbleAlert release];
return 0;
}
else
{
NSString *urlString=#"http:getCustomerList.jsp";
urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[dataParser parseXMLFileAtURL:[NSURL URLWithString:urlString]];
NSMutableArray *list =[dataParser getCustomerListFromParser];
printf("\n url for Customer List%s",[urlString UTF8String]);
printf("\n Customer List %d",[list count]);
return list;
}
}
I am sending parameter to url to return repctive list when it returns zero I am dispalying alert in view controller.
but when server is not working properly then how to display this alert.
Please help me out of this.
Thank you,
Madan mohan.

In my opinion :
First perform the request operation to the server for any response.
Secondly Catch the the response received in a BOOL variable .
Finally when your BOOL variable is TRUE perform the desired operation [Such as parsing..]
Otherwise just show an alert message with a proper error message.

I'm sure there's a perfectly nice way to do it with parseXMLFileAtURL. I don't that way.
What I do know is if you use the excellent ASIHTTPRequest library to make an asynchronous request, all of that stuff is taken care of for you. You create two delegate methods, RequestFinished and RequestFailed, and one of them will be called when the result is clear.
In RequestFinished you'd parse the string portion of the response object.
In RequestFailed you'd display the alert and then decide how to proceed from there.

for this u create the asynchronous request usingNSURLRequest
NSURL *theURL=[[NSURL alloc]initWithString:#"**YOUR URL**"];
NSMutableURLRequest *theRequest = [[NSMutableURLRequest alloc] initWithURL:theURL];
[theRequest setTimeoutInterval:150];
[theURL release];
mURLConnection=[[NSURLConnection alloc]initWithRequest:theRequest delegate:self];
[theRequest release]
and then in their delegate method
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if (mResultData == nil) //mResultData is NSData(member variable)
mResultData = [[NSMutableData alloc] init];
[mResultData setLength: 0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[mResultData appendData:data];
}
// this method calls if their is any problem from server side
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[mResultData release];
mResultData = nil;
[mURLConnection release];
mURLConnection = nil;
//here the show the error
UIAlertView *theAlert=[[UIAlertView alloc]initWithTitle:kAlertTitle message:[error localizedDescription] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[theAlert show];
[theAlert release];
}
(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//here u could send mResulData for parsing
// create NSXMLParser
}

Related

NSURLConnection doesn't receive data when creating many downloading objects in iOS5

I have been searching for this problem on the SOF for several days and I still have not found the solution (say the same problem) yet.
I'm making and app that downloads 5 images simultaneously in an URL list (each image is on a different server).
I have an ImageDownloader class subclasses NSOperation and implements the NSURLConnectionDataDelegate.
So that I can add an instance of ImageDownloader to an operationQueue in the ViewController and it will run in a separate thread under the operationQueue. The line that add the downloader to the operationQueue is here:
downloader = [[ImageDownloader alloc] init];
[downloader downloadImageWithURL:[controller.URList objectForKey:[NSString stringWithFormat:#"%d",downloadIndex]] queue:queue andTag:downloadIndex + 100]; //my custom initialize
downloader.delegate = self;
[queue addOperation:downloader]; //use the addOperation method
Everything works fine in iOS6 but messed up in iOS5 (5.0 on my test device and 5.1 on my SDK), it just doesn't receive any response nor data by performing the methods didReceiveResponse and didReceiveData at all (these 2 methods are not jumped in).
After the timeout was exceeded, the runloop jumps into didFailWithError method and the program stalls.
As I understand, this means the runloop still runs right?
I tried to print out the error and all I got is: The request timed out.
When I reduce the number of downloading instances to 2 then it runs, but not with >=3 downloading instances.
One more information is that my network connection does limit the number of connection. But it work fine in iOS6, why it just doesn't work on iOS5?
I can still load the web in the simulator while the app is downloading.
So what kind of problem is this and how can I get over this problem?
Thanks in advance.
*Update:* as there are many classes and the problem's not been clearly detected yet, I will share here the whole project. You can download it directly from here:
DownloadingImage
As I just found out, if you're using credentials there is a chance that the server will reject them randomly every once in a while. So if you have a check to make sure previousFailureCount == 0 then you will most likely have a bug.
I've just figured out where my problem is, but not really understand why.
In my ImageDownloader class, I set up a runloop with done and currentRunLoop variables.
In the main method, I have a while loop for forcing the currentRunLoop run.
As I remove those "runLoop" stuffs, the app runs smoothly on both iOS6 and iOS5.
So change the entire ImageDownloader.m with these lines then it works (I commented out some useless (say harmful) lines):
//
// ImageLoader.m
// DownloadImagesTableView
//
// Created by Viet Ta Quoc on 6/25/13.
// Copyright (c) 2013 Viet Ta Quoc. All rights reserved.
//
#import "ImageDownloader.h"
#implementation ImageDownloader
#synthesize downloadData,delegate,queue,done,customTag;
NSRunLoop *currentRunLoop;
-(void)downloadImageWithURL:(NSString *)imageUrl queue:(NSOperationQueue*)opQueue andTag:(int)tag{
self.customTag= tag;
self.queue = opQueue;
// self.done = NO;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:imageUrl] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[connection start];
// currentRunLoop = [NSRunLoop currentRunLoop];
NSLog(#"Start downloading image %d...",customTag);
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(#"Received response...");
downloadData=[[NSMutableData alloc] initWithLength:0];
expectedDataLength=[response expectedContentLength];
NSLog(#"Image %d size: %lld kb",customTag,[response expectedContentLength]/1024);
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
float receivedLenght = [data length];
receivedDataLength=(receivedDataLength+receivedLenght);
float progress=(float)receivedDataLength/(float)expectedDataLength;
[delegate updateProgess:progress andIndex:[NSIndexPath indexPathForRow:customTag-100 inSection:0]];
[self.downloadData appendData:data];
// NSLog(#"Percentage of data received of tag %d: %f %%",self.customTag,progress*100);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
[delegate finishedDownloadingImage:downloadData andTag:customTag];
// done = YES;
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Warning" message:#"Network Connection Failed?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil, nil];
// NSLog(#"%#",[error debugDescription]);
NSLog(#"Connection failed! Error - %# %#",[error localizedDescription],[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
[alert show];
}
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
NSLog(#"Got here *(*&(**&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&");
}
-(void)main{
// do{
//// NSLog(#"Running....1");
// [currentRunLoop runUntilDate:[NSDate distantFuture]];
// // [currentRunLoop run];
// } while (!done);
// [currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
}
#end
Thank you guys for your supports.
==================================================================================
P/s: for anyone who interested in this problem, I update here my entire solution: DownloadImage_Final

iphone - return fbid to use it in json web service to receive data

I've been looking around, saw similar posts, but nothing like this that could give me answers. This is my setup and flow of the app:
User has to login via Facebook, using Facebook Graph. LoginView is presented modally, non animated
When user logins I can retrieve FBID and I use this fbid to send it to my web service (REST)
Web service gets the FBID from the NSURL and matches it with database to retrieve other user info
Using JSONserialization i parse the JSON received from web service and display it in the view
PROBLEM: Everything returns NULL except FBID that I get from Facebook. BUT, if I logout from Facebook and then login, that's when it works.
Here is my code:
viewDidAppear method:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:NO];
if (FBSession.activeSession.isOpen) {
[self populateUserDetails];
}
//Connect to WebService
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://atnightcorp.com/api/member/id/%#/format/json", fbid]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection connectionWithRequest:request delegate:self];
NSArray *pics = [member valueForKeyPath:#"photos"];
NSString *picCount = [NSString stringWithFormat:#"%d", [pics count]];
[photosCount setTitle:picCount forState:UIControlStateNormal];
NSLog(#"PHOTO: %#", picCount);
NSLog(#"FB: %#", fbid);
}
I tried putting NSURL request and connection code in viewDidLoad, but then I don't get anything back.
My NSURLConnection methods:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
data = [[NSMutableData alloc]init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData
{
[data appendData:theData];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
member = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
UIAlertView *errorView = [[UIAlertView alloc]initWithTitle:#"Error" message:#"The download could not complete. Please make sure you are connected to internet" delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[errorView show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
The populateUserDetails method that you have seen above:
- (void)populateUserDetails
{
if (FBSession.activeSession.isOpen) {
[[FBRequest requestForMe] startWithCompletionHandler:
^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *error) {
if (!error) {
self.userProfileImage.profileID = user.id;
self.navigationItem.title = user.name;
self.fbid = user.id;
}
}];
}
}
This method basically sets the FBID once user is logged in. Other important things you should know that could help you understand my project:
FBID is set as NSString property in my .H file
All facebook connect thing goes on in AppDelegate
I need to dynamically set the NSURL after I find out who the user is.
if I manually input FBID in NSURL, then it works.
everything should be executed when user logins, I think that the timing of retrieving fbid and receiving data from web service is wrong but I can't get to fix it.
IF you need anything else, I will elaborate more and post more code if needed. -
PLEASE HELP as I've been looking for answers for last 3 days.
Your problem is that the populateUserDetails is called and it returns without waiting the code to be executed (because it's an async task with a completition handler, and when you call the NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://atnightcorp.com/api/member/id/%#/format/json", fbid]]; for the first time, the fbid is nuil or not set properly (also you should use self.fbid not fbid since fbid is a property).
So you should try to move the whole code that is handling the request from viewDidAppear into a separate method and you should call that method from startWithCompletionHandler after you set the line with self.fbid = user.id
Also call [super viewDidAppear:animated]; not with NO param (this won't solve your problem but this is the right way to do it)

How to trigger an action after a certain amount of time?

In my app i want to display an error message if the network connection is too slow after few seconds. How should i implement this?
Here's the code:
-(void)setProjectID:(NSString *)newProject {
[self willChangeValueForKey:#"projectID"];
[projectID release];
projectID = [newProject copy];
[self didChangeValueForKey:#"projectID"];
// Since we have an ID, now we need to load it
NSInvocation *returnInvocation = [NSInvocation invocationWithMethodSignature:
[Detail instanceMethodSignatureForSelector:#selector(configureView:)]];
[returnInvocation setTarget:self];
[returnInvocation setSelector:#selector(configureView:)];
[returnInvocation retainArguments];
fetch = [[WBWDocumentFetcher alloc] init];
[fetch retrieveDocument:[NSURL wb_URLForTabType:PROJECT_DETAILS inProject:projectID] returnBy:returnInvocation];
}
-(void)configureView:(NSDictionary *)serverResult
{
}
Thanks,
You want to use performSelector:afterDelay: or possibly performSelector:withObject:afterDelay:.
Then, at the beginning of the method called, check to see if the page has loaded. If not, then display a UIAlertView and cancel the load.
If you are using NSURLRequest for requesting server than use following code to judge time out.
//In this you can set timeoutinterval for request
NSURLRequest* request = [NSURLRequest requestWithURL:yourURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
//If request is failing for time out reason you can check that and alert user accordingly.
-(void)connectionFailed:(NSError *)error
{
UIAlertView *objAlert = [[UIAlertView alloc] init];
[objAlert setTitle:#"Internet Connection"];
[objAlert addButtonWithTitle:#"Ok"];
if([error code] == -1001 || [[error localizedDescription] isEqualToString:#"timed out"]){
[objAlert setMessage:#"Request Timed Out."];
[objAlert show];
}
}

using NSURLConnection instead of stringWithContentsOfURL

Guys, I was retrieving an XML response from a .php script on my server using the following code:
NSString *xmlString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString]
encoding:NSUTF8StringEncoding error:&error];
and
//tried also: if(error)
if(!xmlString)
{
NSString * errorString = [NSString stringWithFormat:#"Unable to download xml data (Error code %i )", [error code]];
UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:#"Error loading content" message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
[errorAlert release];
}
//*** now I have a touchXML xPath query code that extracts what I need from XML
My .php script wasn't working today and my iApp was freezing without any alerts, errors or notifications? I thought that the code above will handle errors but it doesn't???
A) Then what type of error does it catch?
Then I remembered that i I should try working with NSURLConnection and its delegate methods to catch any error that occurs.
//Inside viewDidLoad method
NSMutableData *responseData = [[NSMutableData alloc] init];
NSURL *baseURL = [[NSURL URLWithString:self.chosenDrawRss] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:baseURL];
[[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
NSString *xmlString = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
The problem I had using this approach was that app ran the Connection in the background and continued executing the rest of the code found in viewDidLoad, so I had to reorganize my code a bit by moving it to another method that I call from delegate method connectionDidFinishLoading. The problem I have is that my delegate methods are not called. Well, all except didFailWithError: if I try to load URL that doesn't exist.
UPDATE:
delegate methods are called but it takes one minute or so for delegate method to be called and until alert message pops out...
B) Could I use stringWithContentsOfURL and still have an alert to the user if anything happens?
C) If not, then I need help with setting up NSURLConnection approach? I mean, what I'm missing here is why aren't my delegate methods called?
I truly hope my questions make sense :D
L
If your delegate method is called in didFailWithError then i suppose it will even be called in
connectionDidFinishLoading. Check by enabling a breakpoint in the delegate methods and track the flow. It may have happened the function returns before you call the delegate.
NSString *xmlString = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding]
should be called in your delegate connectionDidFinishLoading method and in
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
I dont see why the alert should pop up after a minute unless you are doing some processing before displaying it.

NSURLRequest converting NSData to an array

I need to convert data received from the web via an array in a PHP script into an array that I can pull values out of. Here's my code!
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
//NSString *payloadAsString = [NSString stringWithUTF8String:[receivedData bytes]];
NSArray *payloadAsString = [NSKeyedUnarchiver unarchiveObjectWithData:receivedData];
[payloadAsString finishEncoding];
verified = [payloadAsString objectAtIndex:0];
NSLog(#"logging");
//NSString *no = [[NSString alloc] init stringWithCString:verified];
NSLog(#"%#", verified);
if([verified isEqualToString:#"admin"]){
NSLog(#"test admin");
[self performSelector:#selector(changeViewAdmin) withObject:nil afterDelay:0.05];
}
if([verified isEqualToString:#"user"]){
NSLog(#"test user");
[self performSelector:#selector(changeView) withObject:nil afterDelay:0.05];
}
if([verified isEqualToString:#"No"]){
NSLog(#"test no");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Invalid UserName/Password combination!"
delegate:self
cancelButtonTitle:#"Okay"
otherButtonTitles:nil];
[alert show];
[alert release];
}
[payloadAsString release];
//NSLog(#"%#", verified);
// INSERT GOOGLE MAPS URL REQUEST HERE
/*if(requestType == 1){
NSString* addressText = payloadAsString;
// URL encode the spaces
addressText = [addressText stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding];
NSString* urlText = [NSString stringWithFormat:#"http://maps.google.com/maps?q=%#", addressText];
// lets throw this text on the log so we can view the url in the event we have an issue
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlText]];
// */
//
//}
[connection release];
self.receivedData = nil;
}
Unfortunately, my console returns null and asks if I've put the -finishencoding method in. Question is, if that's correct, where would I do so?
PS: Another question, is if I'm retrieving an array of data from a database, is a PHP script the best way to go? Thank you.
1) Of all this code the only string relevant to your question is
NSArray *payloadAsString = [NSKeyedUnarchiver unarchiveObjectWithData:receivedData];
I really doubt that PHP script returns you data in NSKeyedUnarchiver-compatible format. I believe the only reason you don't get NSInvalidArgumentException exception from this method is that receivedData is nil (did you initialize it anywhere?). Try to make a string from what you receive like this
[[[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding] autorelease]
and log it. From this I hope it will be clear how to parse response.
2) Do not name NSArray instances like 'blahBlahString'. Strings and arrays are completely different.
NSKeyedUnarchiver can only unarchive instances which are produced by instances of the NSKeyedArchiver class.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSKeyedUnarchiver_Class/index.html