I have an error while reading XML files for my iPhone app. I have a new feature on my iPhone app that reads my RSS feed. Everything looks good by but I have this issue:
Error while loading rss. Please check your Internet connection
Here's my code:
- (BOOL) readRSS {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
BOOL success = NO;
NSXMLParser *parser = nil;
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://rss.domain.com/%#.xml", self.currentPage]];
parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
success = [parser parse];
[parser release];
[pool drain];
return success;
}
Then I have this code:
- (void) cleartbl:(NSInteger)type {
[[[self rssParser] rssItems] removeAllObjects];
[_tableView reloadData];
if(type == 1) {
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"RSS Feed"
message:#"Error while loading rss. Please check your Internet connection."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
[alert release];
}
Then i assign:
if([elementName isEqualToString:#"title"]){
self.currentItem.title = self.currentItemValue;
}
What is my issue, am I missing something?
The code provided looks good for me, what I would do first is to check if your RSS is valid. I think you have an RSS issue here. You can use the RSS Validation to make sure everything looks good.
I would recommend to sanitize your RSS, keep it very simple, if you only want to display news or articles use letters and numbers in your text and use SEO friendly URLs.
This will simplify the data you are loading from your app and avoid errors like special characters.
Try with a simple RSS with one entry to start and you will see if your code has errors.
Related
I'm taking xml response from service url and I want to display error, when network connection fails. So I display the UIAlertView, but this alertView is getting displayed after the rest of process is completed. I want it to be shown immediately.
In android, if network connection fails, it will display an error alert that "Unfortunately app name has terminated". Is there anything of such for iPhone? If not I want to show alertview and stop the rest of the process.
This is the code I'm working on:
if (responseData!= NULL)
{
response = [[NSString alloc] initWithData:responseData
encoding:NSUTF8StringEncoding ];
NSLog(#"Response Code:%d",[urlResponse statusCode]);
if([urlResponse statusCode ]>=200 && [urlResponse statusCode]<300)
{
NSLog(#"Response:%#",response);
}
}
else
{
NSLog(#"Failed to send request: %#", [error localizedDescription]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Unfornately stopped.Try Again " message:#"" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
parser =[[NSXMLParser alloc]initWithData:responseData];
[parser setDelegate:self];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
currentHtmlElement=#"1";
[parser parse];
[parser release];
In my code if it fails to send request, then NSLog gets printed and alertView code is executed. At the same time I want to stop the rest of the process i.e initialising a parser and doing the rest of operation.
How can I do it?
Very simple... Move your parse code inside if block.
if (responseData!= NULL)
{
response = [[NSString alloc] initWithData:responseData
encoding:NSUTF8StringEncoding ];
NSLog(#"Response Code:%d",[urlResponse statusCode]);
if([urlResponse statusCode ]>=200 && [urlResponse statusCode]<300)
{
NSLog(#"Response:%#",response);
}
parser =[[NSXMLParser alloc]initWithData:responseData];
[parser setDelegate:self];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
currentHtmlElement=#"1";
[parser parse];
[parser release];
}
else
{
NSLog(#"Failed to send request: %#", [error localizedDescription]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Unfornately iCloudBiz has stopped.Try Again " message:#"" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
By the way... You mentioned your Android's app behavior as follows
In android if network connection fails it will display an error alert that Unfortunatly app name has terminated.
Please understand that this behavior is an abnormal behavior. This is called a CRASH and you should handle this appropriately. If network is disconnected app should display a message without terminating/crashing :)
You should use Reachability class to check for whether internet connection is available or not
this is sample code to understand how it works
Reachability *reachability = [Reachability reachabilityForInternetConnection];
NetworkStatus internetStatus = [reachability currentReachabilityStatus];
if (internetStatus != NotReachable) {
//my web-dependent code
}
else {
//there-is-no-connection warning
}
in iphone,
i call one webservice For login checking...
When Application Is Underprocess ,, I Show UIAlertview With UIActivityIndicatorView
using thread,,
now i want to enable cancel button ,, means during the process if i want to cancel that process,, then my apps teminates webservice calling
but when i enable cancel button then ERROR OCccur,
Any One Can Help
My COde Is
-(NSMutableString*) getLoginMessage:(NSString*) UserName : (NSString *) Password
{
[NSThread detachNewThreadSelector:#selector(showAlertMethod) toTarget:self withObject:nil];
NSArray *Keys =[[NSArray alloc] initWithObjects:#"LoginName",#"PassWord",nil];
NSArray *KeyValue =[[NSArray alloc] initWithObjects:UserName,Password,nil];
operationName=[[NSString alloc] init];
operationName =#"ClientLogin";
NSString *StrService=[[NSUserDefaults standardUserDefaults] objectForKey:#"WebService"];
NSURL *WebServiceUrl=[WebServiceHelper generateWebServiceHTTPGetURL:StrService : operationName : Keys :KeyValue];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:WebServiceUrl];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser setDelegate:self];
[parser parse];
[Keys release];
[KeyValue release];
[StrService release];
[WebServiceUrl release];
//[parser release];
[NSThread detachNewThreadSelector:#selector(dismissAlertMethod) toTarget:self withObject:nil];
return Result;
}
-(void)showAlertMethod
{
NSAutoreleasePool *pool1=[[NSAutoreleasePool alloc]init];
progressAlert = [[UIAlertView alloc] initWithTitle:#"Loging in...\nPlease wait...\n" message:#"" delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
CGRect alertFrame = progressAlert.frame;
UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicator.frame = CGRectMake(135,alertFrame.size.height+75, alertFrame.size.width,30);
activityIndicator.hidden = NO;
activityIndicator.contentMode = UIViewContentModeCenter;
[activityIndicator startAnimating];
[progressAlert addSubview:activityIndicator];
[activityIndicator release];
[progressAlert show];
[pool1 release];
}
-(void)dismissAlertMethod
{
NSAutoreleasePool *pool2=[[NSAutoreleasePool alloc]init];
[progressAlert dismissWithClickedButtonIndex:0 animated:YES];
[pool2 release];
}
There are some major flaws in how you attack the problem. Firstly you should not detach new threads to show and hide the alert view, all UIKit classes must be called form the main thread (only few documented exceptions exist).
What you want is an API designed to be asynchronous for dispatching the login request. I would suggest you use an Sync-Async pattern for this. I have written a longer blog post on this topic here: http://blog.jayway.com/2011/04/28/sync-asyn-pair-pattern-easy-concurrency-on-ios/
In essence I believe you want two public methods:
-(NSString*)loginMessageWithName:(NSString*)name
password:(NSString*)password
error:(NSError**)error;
-(NSOperation*)loginMessageWithName:(NSString*)name
password:(NSString*)password
delegate:(id<LoginMessageDelegate>)delegate;
The first method is synchronous, implement it as straightforward as you like, no threads on any thing, just make it work.
The second method is a wrapper that instantiates a NSOperation objects and puts it on some queue. Returning the operation allows you to cancel it, but the result will be returned on the delegate. The delegate will probably need to look something like this:
#protocol LogonMessageDelegate <NSObject>
-(void)didReceiveLoginMessage:(NSString*)message;
-(void)failedLoginMessageWithError:(NSError*)error;
#end
The implementation of loginMessageWithName:password:delegate: is very straight forward:
NSOperation* op = [[LoginMessageOperation alloc] initWithName:name
password:password
delegate:delegate];
[myOperationQueue addOperation:op];
return [op autorelease];
Most of the work will be done in your NSOperation subclass' main method. This is where you call the synchronious implementation, check for cancelation, and call back to the delegate if needed. Probably something like this:
-(void)main {
NSError* error = nil;
NSString* message = [logonMessageManager logonWithName:name
password:password:
error:&error];
if (![self isCancelled]) {
if (message) {
[delegate performSelectorOnMainThread:#selector(didReceiveLoginMessage:)
withObject:message
waitUntilDone:NO];
} else {
[delegate performSelectorOnMainThread:#selector(didReceiveLoginMessage:)
withObject:error
waitUntilDone:NO];
}
}
}
Then setup and handle the alert view on the main thread. Call [operation cancel] if the user cancels, or dismiss the alert when the delegate receives a callback.
I am creating application that simply reads data from an XML file and displays it in a table view.
I created a "refresh" button when clicked i want it to redownload the xml file and display it again however it seems to crash my application if there is a XML file already downloaded.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ipb = [[IPB alloc] init];
sectionTitle=[[NSMutableArray alloc]init];
currentURL=#"http://localhost:8888/xml/Sinnergy.xml";
[self reloadTableView];
[window makeKeyAndVisible];
return YES;
}
-(void)reloadTableView
{
pathURL = [NSURL URLWithString:currentURL];
parser = [[NSXMLParser alloc] initWithContentsOfURL:pathURL];
[parser setDelegate:self];
[parser parse];
[mainTableView reloadData];
}
You are leaking the parser, and if its an instance variable it might cause issues. You should go
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:pathURL];
[parser setDelegate:self];
[parser parse];
[parser release];
Also you are asking the parser to start parsing, but at that point of time you shouldn't be reloading the table, it should be in your
- (void)parserDidEndDocument:(NSXMLParser *)parser
delegate method. Try that and if it still crashes post the crash report
I am developing an application in which I am doing XML parsing. I found an error in the [xmlparse parse] method.
Error:
[NSCFString bytes]: unrecognized selector sent to instance 0x3df6310
2010-04-30 00:09:46.302 SPCiphone2[4234:1003] void SendDelegateMessage
(NSInvocation*): delegate (<CFNotificationCenter 0x3d09670 [0x87dca0]>)
failed to return after waiting 10 seconds. main run loop mode:
kCFRunLoopDefaultMode
Code snippet:
responseOfWebResultData = [[NSMutableString alloc]
initWithData:responseData
encoding:NSUTF8StringEncoding];
NSLog(#"result: %#", responseOfWebResultData);
// starting the XML parsing
if (responseOfWebResultData) {
#try {
xmlParser = [[NSXMLParser alloc] initWithData:responseOfWebResultData];
[xmlParser setDelegate:self];
[xmlParser setShouldResolveExternalEntities:YES];
[xmlParser parse];
[responseOfWebResultData release];
}
#catch (NSException *e) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Please"
message:[e reason]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}
You should not be passing in a NSString* into initWithData:. You should do this:
xmlParser = [[NSXMLParser alloc] initWithData:responseData];
The error says that you're sending the message bytes to an instance of NSCFString, which is a NSString*, even though you declared it as a NSMutableString*, because this is a dynamically typed language but the class types are not automatically converted if you try to cast it to something else.
I am using a private MBProgressHUD
Now I am using the indicator view on my add button in which I am calling my addrecord service .
UIWindow *window = [UIApplication sharedApplication].keyWindow;
HUD = [[MBProgressHUD alloc] initWithWindow:window];
// Add HUD to screen
[window addSubview:HUD];
// Regisete for HUD callbacks so we can remove it from the window at the right time
HUD.delegate = self;
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(addingToFavorites) onTarget:self withObject:nil animated:YES];
the adding to favorites method :
NSURL *url = [NSURL URLWithString:urlstring];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];
[request setHTTPMethod:#"GET"];
//[request setTimeoutInterval:10];
//NSURLResponse *response = nil;
// NSError *error = nil;
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
NSData *data1= [NSURLConnection sendSynchronousRequest:request
returningResponse:nil error:nil];
if(data1 == nil)
{
doneFlag = NO;
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Alert"
message:#"The network is not available.\n Please check the Internet connection."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
else
{
doneFlag = YES;
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Confirmation"
message:#"Added To favorites"
delegate:nil
cancelButtonTitle:#"OKAY"
otherButtonTitles:nil];
[alert show];
alert = nil;
[alert release];
}
[request release];
This is all running fine except the instruments gives leak of the uialertview may be it is conflicting with the mbprogreshud.
So I thought to remove the alert from the calling method and put it in the caller the method like this:
the caller method now :
UIWindow *window = [UIApplication sharedApplication].keyWindow;
HUD = [[MBProgressHUD alloc] initWithWindow:window];
// Add HUD to screen
[window addSubview:HUD];
// Regisete for HUD callbacks so we can remove it from the window at the right time
HUD.delegate = self;
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(addingToFavorites) onTarget:self withObject:nil animated:YES];
//it should wait for the above line to be executing ******* then to exexute the be //below condition but how ?
if (doneFlag == NO) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Alert"
message:#"The network is not available.\n Please check the Internet connection."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
} else {
[favoritesButton setTitle:#"Remove" forState:UIControlStateNormal];
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Confirmation"
message:#"Added To favorites"
delegate:nil
cancelButtonTitle:#"OKAY"
otherButtonTitles:nil];
[alert show];
alert = nil;
[alert release];
}
the adding to favorites method :
NSURL *url = [NSURL URLWithString:urlstring];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];
[request setHTTPMethod:#"GET"];
//[request setTimeoutInterval:10];
//NSURLResponse *response = nil;
// NSError *error = nil;
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
NSData *data1= [NSURLConnection sendSynchronousRequest:request
returningResponse:nil error:nil];
if(data1 == nil)
{
doneFlag = NO;
}
else
{
doneFlag = YES;
}
[request release];
In the launching of the progresshud thread is detaching something like this :
[NSThread detachNewThreadSelector:#selector(launchExecution) toTarget:self withObject:nil]
Now My question is that If I follow the first scenario . How can I assure the the alertview leak will not come
Or If I am following the second scenario How can I assure the if condition will be executed after completing this line executed :
[HUD showWhileExecuting:#selector(addingToFavorites) onTarget:self withObject:nil animated:YES];
Regarding the first scenario, it is in general a bad idea to do UI updates from threads other than the applications main thread. UIKit is NOT thread safe and doing threaded UI updates can cause all sorts of strange things to happen. Now, I'm not sure if this is the cause for the leak but I would avoid showing an UIAlertView in addingToFavorites. Use performSelectorOnMainThread or the second scenario described below.
Regarding the second scenario, move everything below the showWhileExecuting call to the hudWasHidden delegate method. At this point you can be sure that your code was fully executed and the doneFlag was set.
To use performSelectorOnMainThread, define a new method, put your code in it and than call performSelectorOnMainThread.
I.e.,
- (void)showAlert {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Alert" message:#"The network is not available.\n Please check the Internet connection." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
Call with,
[self performSelectorOnMainThread:#selector(showAlert) withObject:nil waitUntilDone:NO];
I would go with the second scenario though.
Other answers notwithstanding, you were creating the UIAlertView leak with this sequence:
[alert show];
alert = nil;
[alert release];
The last two lines should be swapped:
[alert show];
[alert release];
alert = nil;