I am using hpple from git for parsing HTML. It working fine. But when I get the parsed NSString I found that in this string double inverted comma (")and single (') are replaced by some other symbol like ,Äô. How can I get the correct string? I have tried to replace these characters but its not working.
Check out this link it solved my problem
https://github.com/mwaterfall/MWFeedParser
Here the steps to add the code
Add all the classes,except detailtableviewcontroller and Rootviewcontroller from the code you downloaded from the link. Then add #import "MWFeedParser.h" in your.h file where you are parsing .Then add // Parsing
MWFeedParser *feedParser;
NSMutableArray *parsedItems;
// Displaying
NSArray *itemsToDisplay;
NSDateFormatter *formatter;and /***mwfeed (*/
#property (nonatomic, retain) NSArray *itemsToDisplay;
/*------------*/
Then in .m add the codeformatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
parsedItems = [[NSMutableArray alloc] init];
self.itemsToDisplay = [NSArray array];
// Parse
NSURL *feedURL = [NSURL URLWithString:#"http://feeds.feedburner.com/yummydietfood?format=xml"];
feedParser = [[MWFeedParser alloc] initWithFeedURL:feedURL];
feedParser.delegate = self;
feedParser.feedParseType = ParseTypeFull; // Parse feed info and all items
feedParser.connectionType = ConnectionTypeAsynchronously;
[feedParser parse];
#pragma mark -
#pragma mark MWFeedParserDelegate
- (void)feedParserDidStart:(MWFeedParser *)parser {
//[UIApplication sharedApplication].networkActivityIndicatorVisible=YES;
NSLog(#"Started Parsing: %#", parser.url);
}
- (void)feedParser:(MWFeedParser *)parser didParseFeedInfo:(MWFeedInfo *)info {
NSLog(#"Parsed Feed Info: “%#”", info.title);
//self.title = info.title;
}
- (void)feedParser:(MWFeedParser *)parser didParseFeedItem:(MWFeedItem *)item {
NSLog(#"Parsed Feed Item: “%#”", item.title);
if (item) [parsedItems addObject:item];
}
- (void)feedParserDidFinish:(MWFeedParser *)parser {
NSLog(#"Finished Parsing%#", (parser.stopped ? #" (Stopped)" : #""));
self.itemsToDisplay = [parsedItems sortedArrayUsingDescriptors:
[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:#"date"
ascending:NO] autorelease]]];
[UIApplication sharedApplication].networkActivityIndicatorVisible=YES;
//[self performSelector:#selector(loadData)];
[self performSelector:#selector(loadDataWithOperation)];
}
- (void)feedParser:(MWFeedParser *)parser didFailWithError:(NSError *)error {
NSLog(#"Finished Parsing With Error: %#", error);
UIAlertView *erroralert = [[UIAlertView alloc]initWithTitle:#"Error!" message:#"Problem connecting server, try again in few minutes" delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil];
[erroralert show];
[erroralert release];
self.itemsToDisplay = [NSArray array];
[parsedItems removeAllObjects];
self.tbl.userInteractionEnabled = YES;
[self.tbl reloadData];
}
and where you need the data parsed by the parser called this line code
if (item) {
NSString *itemTitle = item.title ? [item.title stringByConvertingHTMLToPlainText] : #"[No Title]";
lbl.text = itemTitle;
}
else {
lbl.text=#"No Title";
}
Check your encoding; bottom-line is you're probably getting the HTML in UTF-8 and the string in ISO-8859-1.
Related
I'm using three20 to create image viewer. First i'm creating list of albums from the sql db and when user selects any album, its url string is passed to the this code that creates thums of available pics on network using XML Parser. everything works fine but when user goes back to the album list and selects another album. app crashes with 'Thread 1: Program received singal: "EXC+BAD_ACCESS" in main.m. plus XCode Product Analyze gives potential memory leak where i'm creating photoSource in the viewDidLoad. Here is the code
#import "AlbumController.h"
#import "PhotoSource.h"
#import "Photo.h"
#import "AlbumInfo.h"
#import "AlbumDatabase.h"
#implementation AlbumController
#synthesize albumName;
#synthesize urlAddress;
#synthesize images;
- (void)viewDidLoad
{
[super viewDidLoad];
// NSLog(#"%#", self.urlAddress);
[self createPhotos]; // method to set up the photos array
self.photoSource = [[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:self.albumName
photos:images
photos2:nil];
self.navigationController.navigationBar.tintColor = [UIColor blackColor];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// release and set to nil
}
-(void)createPhotos
{
if ([stories count] == 0)
{
NSString *path = self.urlAddress;
[self parseXMLFileAtURL:path];
}
images = [NSMutableArray arrayWithCapacity:[stories count]]; // needs to be mutable
for (int i = 0; i < [stories count]; i++)
{
NSString *img = [[stories objectAtIndex:i] objectForKey:#"image"];
img = [img stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
//NSString * caption = [[stories objectAtIndex:i] objectForKey:#"caption"];
//caption = [caption stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
[images addObject:[[[Photo alloc] initWithURL:img smallURL:img size:CGSizeMake(320, 212)] autorelease]];
}
}
#pragma mark -
#pragma mark XML Parser Implementation
- (void)parserDidStartDocument:(NSXMLParser *)parser{
//NSLog(#"found file and started parsing");
}
- (void)parseXMLFileAtURL:(NSString *)URL
{
stories = [[NSMutableArray alloc] init];
//you must then convert the path to a proper NSURL or it won't work
NSURL *xmlURL = [NSURL URLWithString:URL];
// here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
// this may be necessary only for the toolchain
rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
[rssParser setDelegate:self];
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString * errorString = [NSString stringWithFormat:#"Unfortunately it is not possible to load Pictures. Please check Internet Connection. (Error code %i )", [parseError code]];
//NSLog(#"error parsing XML: %#", errorString);
UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:#"Failed to load the feed." message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
[errorAlert release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
//NSLog(#"found this element: %#", elementName);
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) {
// clear out our story item caches...
item = [[NSMutableDictionary alloc] init];
currentCaption = [[NSMutableString alloc] init];
//currentThumbnail = [[NSMutableString alloc] init];
currentImage = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
//NSLog(#"ended element: %#", elementName);
if ([elementName isEqualToString:#"item"]) {
// save values to an item, then store that item into the array...
//[item setObject:currentThumbnail forKey:#"thumbnail"];
//[item setObject:currentCaption forKey:#"caption"];
[item setObject:currentImage forKey:#"image"];
[stories addObject:[[item copy] autorelease]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
// save the characters for the current item...
if ([currentElement isEqualToString:#"thumbnail"]) {
//[currentThumbnail appendString:string];
}// else if ([currentElement isEqualToString:#"caption"]) {
//[currentCaption appendString:string];
//}
else if ([currentElement isEqualToString:#"image"]) {
[currentImage appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSLog(#"all done!");
NSLog(#"stories array has %d items", [stories count]);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
if (toInterfaceOrientation == UIInterfaceOrientationPortrait ||
toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
return YES;
}
else
{
return NO;
}
}
#pragma mark -
#pragma mark Memory Management
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[currentElement release];
[rssParser release];
[stories release];
[item release];
[currentCaption release];
//[currentThumbnail release];
[currentImage release];
[images release];
[stories release];
[super dealloc];
}
#end
and here is the didSelectRowAtIndexPath thats pushing this view
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
AlbumInfo *info = [_albumInfos objectAtIndex:indexPath.row];
AlbumController *albumController = [[AlbumController alloc] init];
albumController.urlAddress = info.address;
albumController.albumName = info.name;
[self.navigationController pushViewController:albumController animated:YES];
[albumController release];
}
Here is the code for AlbumController.h
#import <Foundation/Foundation.h>
#import "Three20/Three20.h"
#interface AlbumController : TTThumbsViewController <NSXMLParserDelegate>
{
NSString *albumName;
NSString *urlAddress;
// images
NSMutableArray *images;
// parser
NSXMLParser * rssParser;
NSMutableArray * stories;
NSMutableDictionary * item;
NSString * currentElement;
NSMutableString * currentImage;
NSMutableString * currentCaption;
}
#property (nonatomic, strong) NSString *albumName;
#property (nonatomic, strong) NSString *urlAddress;
#property (nonatomic, retain) NSMutableArray *images;
- (void)createPhotos;
- (void)parseXMLFileAtURL:(NSString *)URL;
#end
used this tutorial http://www.raywenderlich.com/1430/how-to-use-the-three20-photo-viewer
Need help solving this memory leak and need to know why its crashing.
Thanks
Simple. In Xcode 4.0+, Just click-hold on the Run icon, and press Profile. It'll open up Instruments, and you'll want Zombies. Then navigate your app to where the crash happened before, and this time, it'll show up in Instruments with the caller, and all the information about it.
The memory leak in viewDidLoad is caused by the following line:
self.photoSource = [[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:self.albumName
photos:images
photos2:nil];
[PhotoSource alloc] returns an object you own (with a retain count of +1).
initWithType:title:photos:photos2: does not change the retain count.
So viewDidLoad is left with an object it owns, but no pointer to it. To balance the alloc you should send an autorelease message:
self.photoSource = [[[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:self.albumName
photos:images
photos2:nil] autorelease];
i have a note which can share it to evernote,i done it sucessfully.but there is an option called import note.when we tap the import button the notes fromn the evernote has to load in the importpage textview.but my problewm is the note from the evernote appers in xml formate with the note.my code for uploding note to evernote server is
-(IBAction)sendNoteEvernote:(id)sender{
EDAMNote * note = [[[EDAMNote alloc] init]autorelease];
// Setting initial values sent by the user
note.title = #"mybibleapp";
NSMutableString *str = [[NSMutableString alloc] initWithString:#"NOTES:"];
for (int i = 0; i<[appDelegate.notesArray count]; i++) {
NSString * aString = [[NSString alloc] initWithString:[appDelegate.notesArray objectAtIndex:i]] ;
NSString * ENML= [NSString stringWithFormat:#"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n<en-note>%#",aString];
//aString contains the note value
ENML = [NSString stringWithFormat:#"%#%#", ENML, #"</en-note>"];
NSLog(#"%#", ENML);
// Adding the content & resources to the note
[note setContent:ENML];
#try {
[[Evernote sharedInstance] createNote:note];
_acteverbackup.hidden = YES;
_actimageeverbackup.hidden =YES;
}
#catch (EDAMUserException * e) {
_acteverbackup.hidden = YES;
_actimageeverbackup.hidden =YES;
NSString * errorMessage = [NSString stringWithFormat:#"Error saving note: error code %i", [e errorCode]];
proAlertView *alert = [[proAlertView alloc]initWithTitle:#"Evernote" message:errorMessage delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil];
[alert setBackgroundColor:[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0] withStrokeColor:[UIColor colorWithHue:0.0 saturation:0.0 brightness:0.0 alpha:1.0]];
[alert show];
[alert release];
return;
}
i get the note in the everrnote correctly
this is my download or import code
- (void)viewDidLoad
{
[super viewDidLoad];
// Load the EDAMNote object that has guid we have stored in the object
EDAMNote * note = [(Evernote *)[Evernote sharedInstance] getNote:guid];
noteNavigation.topItem.title = [note title];
noteContent.text = [note content];
//noteContent is the textview which display the note
// Adding a back button to close the windows
UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(goBack:)];
UINavigationItem *item = [[[UINavigationItem alloc] init] autorelease];
item.leftBarButtonItem = doneButton;
item.hidesBackButton = YES;
[noteNavigation pushNavigationItem:item animated:NO];
noteNavigation.topItem.title = [note title];
}
noteContent is the textview which display the note ,here am getting this values
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n<en-note>%#",mynote is here</en-note>
i need only mynote is here in this textview. How can I separate this from note?
There's a very nice NSString category that you can use, it's a part of the project MWFeedParser. More specifically, you look for the file NSString+HTML.
The NSString+HTML category now supports XML decoding, you can read about it here.
…NSString+XMLEntities category depreciated and replaced by NSString+HTML with improved HTML character entity encoding/decoding via Google Toolbox for Mac.
This category adds to following methods to the NSString class
- (NSString *)stringByStrippingTags;
- (NSString *)stringWithNewLinesAsBRs;
- (NSString *)stringByRemovingNewLinesAndWhitespace;
- (NSString *)stringByDecodingHTMLEntities;
- (NSString *)stringByEncodingHTMLEntities;
You should be able to transform XML into an NSString in a smart way by using it.
NSString *summary = [[[item.summary stringByStrippingTags] stringByRemovingNewLinesAndWhitespace] stringByDecodingHTMLEntities];
Hope it helps!
I'm going crazy with this my little app... Please help me!!!
this is the source code of the app: Smoking.zip
It only saves a .dat file with an NSMutableArray.
Now, the first time you will launch the app, try to click the cigarette button sometimes: Everything should working fine.
Ok, now close the app, re-open it, and click again on the button. This time the app will crash with the "unrecognized selector sent to instance 0x5d18d60" error.
I was sure the problem was in saving the data, because when i commented the line "[theData writeToFile:dataFilePath atomically:YES];" in the "saveData" method the error disappeared.
Later i discovered that it appears again if i try to read the data from the NSMutableArray.
Please take a moment to check my project and help me, beacause i'm going crazy about that!!
Here's some code:
#import "SmokingAppDelegate.h"
#import "SmokingViewController.h"
#import "Cig.h"
#implementation SmokingAppDelegate
#synthesize window;
#synthesize viewController, dataFilePath, smokeArray;
#pragma mark -
#pragma mark Application lifecycle
- (id) init {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"a.dat"];
[self setDataFilePath:path];
NSFileManager *fileManager = [NSFileManager defaultManager];
if([fileManager fileExistsAtPath:dataFilePath]
) {
//open it and read it
NSLog(#"data file found. reading into memory");
smokeArray = [[NSMutableArray alloc] init];
NSMutableData *theData;
NSKeyedUnarchiver *decoder;
NSMutableArray *tempArray;
theData = [NSData dataWithContentsOfFile:dataFilePath];
decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
tempArray = [decoder decodeObjectForKey:#"smokeArray"];
[self setSmokeArray:tempArray];
[decoder finishDecoding];
[decoder release];
} else {
NSLog(#"no file found. creating empty array");
smokeArray = [[NSMutableArray alloc] init];
[smokeArray insertObject:[[NSNumber alloc] initWithInt:0] atIndex:0];
}
// [self logArrayContents];
return self;
}
- (void) logArrayContents {
for(int j = 1; j < [smokeArray count]; j++) {
int f = [[[smokeArray objectAtIndex:j] num] intValue];
NSLog(#"%i. - %d", j, f);
}
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
-(void) saveData {
NSMutableData *theData;
NSKeyedArchiver *encoder;
theData = [NSMutableData data];
encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];
[encoder encodeObject:smokeArray forKey:#"smokeArray"];
[encoder finishEncoding];
[theData writeToFile:dataFilePath atomically:YES];
[encoder release];
NSLog(#"Saved");
}
#pragma mark -
#pragma mark Memory management
- (void)dealloc {
[viewController release];
[window release];
[dataFilePath release];
[smokeArray release];
[super dealloc];
}
#end
#import "SmokingViewController.h"
#import "SmokingAppDelegate.h"
#import "Cig.h"
#implementation SmokingViewController
#synthesize label;
- (void)viewDidLoad {
[super viewDidLoad];
SmokingAppDelegate *mainDelegate = (SmokingAppDelegate *)[[UIApplication sharedApplication] delegate];
//controlla se il giorno è lo stesso rispetto a quello dell'ultima sigaretta fumata
if ([mainDelegate.smokeArray count] > 1) {
Cig *oldCig = [mainDelegate.smokeArray lastObject];
NSArray *tempArray = [self quando];
if ( [[tempArray objectAtIndex:0] intValue]==[[oldCig.dat objectAtIndex:0] intValue]
&& [[tempArray objectAtIndex:1] intValue]==[[oldCig.dat objectAtIndex:1] intValue]
&& [[tempArray objectAtIndex:2] intValue]==[[oldCig.dat objectAtIndex:2] intValue]
) {
N = [oldCig.num intValue];
}
else {
N = 0;
}
[oldCig release];
[tempArray release];
}
//scrive quante sigarette si sono fumate oggi
label.text = [NSString stringWithFormat: #"Today you smoked %d cigarettes",N];
}
- (IBAction) smoke:(UIButton * ) button {
SmokingAppDelegate *mainDelegate = (SmokingAppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"L'array contiene %d sigarette", [mainDelegate.smokeArray count]-1);
N += 1;
[self addNewCigToArray];
[mainDelegate logArrayContents];
[mainDelegate saveData];
label.text = [NSString stringWithFormat: #"Today you smoked %d cigarettes",N];
}
- (void) addNewCigToArray {
//NSLog(#"new cigarette smoked");
SmokingAppDelegate *mainDelegate = (SmokingAppDelegate *)[[UIApplication sharedApplication] delegate];
Cig *newCig = [[Cig alloc] init];
[newCig setDat:[self quando]];
[newCig setNum:[[NSNumber alloc] initWithInt:N]];
[mainDelegate.smokeArray addObject:newCig];
[newCig release];
//[mainDelegate logArrayContents];
}
- (NSArray *) quando {
NSDateFormatter *timeFormat = [[NSDateFormatter alloc] init];
// 0 - Year
[timeFormat setDateFormat:#"YYYY"];
NSString *year = [timeFormat stringFromDate:[NSDate date]];
// 1 - Month
[timeFormat setDateFormat:#"MM"];
NSString *month = [timeFormat stringFromDate:[NSDate date]];
// 2 - Day
[timeFormat setDateFormat:#"dd"];
NSString *day = [timeFormat stringFromDate:[NSDate date]];
// 3 - Hour
[timeFormat setDateFormat:#"HH"];
NSString *hour = [timeFormat stringFromDate:[NSDate date]];
// 4 - Minute
[timeFormat setDateFormat:#"mm"];
NSString *min = [timeFormat stringFromDate:[NSDate date]];
// 5 - Second
[timeFormat setDateFormat:#"ss"];
NSString *sec = [timeFormat stringFromDate:[NSDate date]];
NSArray *newArray = [[NSArray alloc] initWithObjects:year,month,day,hour,min,sec,nil];
return newArray;
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
Okay, I am an iPhone newbie so take my suggestion in stride. You could try creating an NSData object, initializing it with theData, and then calling writeToFile on the new NSData object instead of the NSMutableData object.
I am parsing an XML file using a custom class that instanciates & uses NSXMLParser. On the first call everything is fine but on the second, third and later calls Instruments show tens of memory leaks on certain lines inside didEndElement, didEndElement and foundCharacters functions.
I googled it and found some people having this issue, but I didn't find anything that could really help me.
My Parser class looks like this :
Parser.h
#interface XMLParser : NSObject {
NSMutableArray *data;
NSMutableString *currentValue;
NSArray *xml;
NSMutableArray *videos;
NSMutableArray *photos;
NSXMLParser *parser;
NSURLConnection *feedConnection;
NSMutableData *downloadedData;
Content *content;
Video *video;
BOOL nowPhoto;
BOOL nowVideo;
BOOL finished;
BOOL webTV;
}
-(void)parseXML:(NSURL*)xmlURL;
-(int)getCount;
-(NSArray*)getData;
//- (void)handleError:(NSError *)error;
//#property(nonatomic, retain) NSMutableString *currentValue;
#property(nonatomic, retain) NSURLConnection *feedConnection;
#property(nonatomic, retain) NSMutableData *downloadedData;
#property(nonatomic, retain) NSArray *xml;
#property(nonatomic, retain) NSXMLParser *parser;
#property(nonatomic, retain) NSMutableArray *data;
#property(nonatomic, retain) NSMutableArray *photos;
#property(nonatomic, retain) NSMutableArray *videos;
#property(nonatomic, retain) Content *content;
#property(nonatomic, retain) Video *video;
#property(nonatomic) BOOL finished;
#property(nonatomic) BOOL nowPhoto;
#property(nonatomic) BOOL nowVideo;
#property(nonatomic) BOOL webTV;
#end
Parser.m
#import "Content.h"
#import "Video.h"
#import "Parser.h"
#import <CFNetwork/CFNetwork.h>
#implementation XMLParser
#synthesize xml, parser, finished, nowPhoto, nowVideo, webTV;
#synthesize feedConnection, downloadedData, data, content, photos, videos, video;
-(void)parseXML:(NSURL*)xmlURL {
/*
NSURLRequest *req = [NSURLRequest requestWithURL:xmlURL];
self.feedConnection = [[[NSURLConnection alloc] initWithRequest:req delegate:self] autorelease];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
*/
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
NSXMLParser *feedParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
//NSXMLParser *feedParser = [[NSXMLParser alloc] initWithData:theXML];
[self setParser:feedParser];
[feedParser release];
[[self parser] setDelegate:self];
[[self parser] setShouldResolveExternalEntities:YES];
[[self parser] parse];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if ([elementName isEqualToString:#"articles"]) {
self.finished = NO;
self.nowPhoto = NO;
self.nowVideo = NO;
self.webTV = NO;
if (!data) {
NSMutableArray *tmp = [[NSMutableArray alloc] init];
[self setData:tmp];
[tmp release];
return ;
}
}
if ([elementName isEqualToString:#"WebTV"]) {
self.finished = NO;
self.nowPhoto = NO;
self.nowVideo = NO;
self.webTV = YES;
if (!data) {
NSMutableArray *tmp = [[NSMutableArray alloc] init];
[self setData:tmp];
[tmp release];
return ;
}
}
if ([elementName isEqualToString:#"photos"]) {
if (!photos) {
NSMutableArray *tmp = [[NSMutableArray alloc] init];
[self setPhotos:tmp];
[tmp release];
return;
}
}
if ([elementName isEqualToString:#"videos"]) {
if (!videos) {
NSMutableArray *tmp = [[NSMutableArray alloc] init];
[self setVideos:tmp];
[tmp release];
return;
}
}
if ([elementName isEqualToString:#"photo"]) {
self.nowPhoto = YES;
self.nowVideo = NO;
}
if ([elementName isEqualToString:#"video"]) {
self.nowPhoto = NO;
self.nowVideo = YES;
}
if ([elementName isEqualToString:#"WebTVItem"]) {
if (!video) {
Video *tmp = [[Video alloc] init];
[self setVideo:tmp];
[tmp release];
}
NSString *videoId = [attributeDict objectForKey:#"id"];
[[self video] setVideoId:[videoId intValue]];
}
if ([elementName isEqualToString:#"article"]) {
if (!content) {
Content *tmp = [[Content alloc] init];
[self setContent:tmp];
[tmp release];
}
NSString *contentId = [attributeDict objectForKey:#"id"];
[[self content] setContentId:[contentId intValue]];
return;
}
if ([elementName isEqualToString:#"category"]) {
NSString *categoryId = [attributeDict objectForKey:#"id"];
NSString *parentId = [attributeDict objectForKey:#"parent"];
[[self content] setCategoryId:[categoryId intValue]];
[[self content] setParentId:[parentId intValue]];
categoryId = nil;
parentId = nil;
return;
}
if ([elementName isEqualToString:#"vCategory"]) {
NSString *categoryId = [attributeDict objectForKey:#"id"];
NSString *parentId = [attributeDict objectForKey:#"parent"];
[[self video] setCategoryId:[categoryId intValue]];
[[self video] setParentId:[parentId intValue]];
categoryId = nil;
parentId = nil;
return;
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (!currentValue) {
currentValue = [[NSMutableString alloc] initWithCapacity:1000];
}
if (currentValue != #"\n")
[currentValue appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSString *cleanValue = [currentValue stringByReplacingOccurrencesOfString:#"\n" withString:#""] ;
if ([elementName isEqualToString:#"articles"]) {
self.finished = YES;
//[content release];
}
if ([elementName isEqualToString:#"article"]) {
[[self data] addObject:[self content]];
[self setContent:nil];
[self setPhotos:nil];
[self setVideos:nil];
/*
[content release];
content = nil;
[videos release];
videos = nil;
[photos release];
photos = nil;
*/
}
if ([elementName isEqualToString:#"WebTVItem"]) {
[[self data] addObject:[self video]];
[self setVideo:nil];
//[video release];
//video = nil;
}
if ([elementName isEqualToString:#"title"]) {
//NSLog(#"Tit: %#",cleanValue);
[[self content] setTitle:cleanValue];
}
if ([elementName isEqualToString:#"vTitle"]) {
[[self video] setTitle:cleanValue];
}
if ([elementName isEqualToString:#"link"]) {
//NSURL *url = [[NSURL alloc] initWithString:cleanValue] ;
[[self content] setUrl:[NSURL URLWithString:cleanValue]];
[[self content] setLink: cleanValue];
//[url release];
//url = nil;
}
if ([elementName isEqualToString:#"vLink"]) {
[[self video] setLink:cleanValue];
[[self video] setUrl:[NSURL URLWithString:cleanValue]];
}
if ([elementName isEqualToString:#"teaser"]) {
NSString *tmp = [cleanValue stringByReplacingOccurrencesOfString:#"##BREAK##" withString:#"\n"];
[[self content] setTeaser:tmp];
tmp = nil;
}
if ([elementName isEqualToString:#"content"]) {
NSString *tmp = [cleanValue stringByReplacingOccurrencesOfString:#"##BREAK##" withString:#"\n"];
[[self content] setContent:tmp];
tmp = nil;
}
if ([elementName isEqualToString:#"category"]) {
[[self content] setCategory:cleanValue];
}
if ([elementName isEqualToString:#"vCategory"]) {
[[self video] setCategory:cleanValue];
}
if ([elementName isEqualToString:#"date"]) {
[[self content] setDate:cleanValue];
}
if ([elementName isEqualToString:#"vDate"]) {
[[self video] setDate:cleanValue];
}
if ([elementName isEqualToString:#"thumbnail"]) {
[[self content] setThumbnail:[NSURL URLWithString:cleanValue]];
[[self content] setThumbnailURL:cleanValue];
}
if ([elementName isEqualToString:#"vThumbnail"]) {
[[self video] setThumbnailURL:cleanValue];
[[self video] setThumbnail:[NSURL URLWithString:cleanValue]];
}
if ([elementName isEqualToString:#"vDirectLink"]){
[[self video] setDirectLink: cleanValue];
}
if ([elementName isEqualToString:#"preview"]){
[[self video] setPreview: cleanValue];
}
if ([elementName isEqualToString:#"thumbnail_position"]){
[[self content] setThumbnailPosition: cleanValue];
}
if ([elementName isEqualToString:#"url"]) {
if (self.nowPhoto == YES) {
[[self photos] addObject:cleanValue];
}
else if (self.nowVideo == YES) {
[[self videos] addObject:cleanValue];
}
}
if ([elementName isEqualToString:#"photos"]) {
[[self content] setPhotos:[self photos]];
//[photos release];
//photos = nil;
self.nowPhoto = NO;
}
if ([elementName isEqualToString:#"videos"]) {
[[self content] setVideos:[self videos]];
//[videos release];
//videos = nil;
self.nowVideo = NO;
}
//[cleanValue release];
//cleanValue = nil;
[currentValue release];
currentValue = nil;
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"Error" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
-(NSArray*)getData {
return data;
}
-(int)getCount {
return [data count];
}
- (void)dealloc {
[parser release];
//[data release];
//[photos release];
//[videos release];
//[video release];
//[content release];
[currentValue release];
[super dealloc];
}
#end
Somewhere in my code, I create an instance of this class :
XMLParser* feed = [[XMLParser alloc] init];
[self setRssParser:feed];
[feed release];
// Parse feed
NSString *url = [NSString stringWithFormat:#"MyXMLURL"];
[[self rssParser] parseXML:[NSURL URLWithString:url]];
Now the problem is that after the first (which has zero leaks), instruments shows leaks in too many parts like this one (they are too much to enumerate them all, but all the calls look the same, I made the leaking line bold) :
in didEndElement :
if ([elementName isEqualToString:#"link"]) {
// THIS LINE IS LEAKING => INSTRUMENTS SAYS IT IS A NSCFString LEAK
[self content] setUrl:[NSURL URLWithString:cleanValue]];
[[self content] setLink: cleanValue];
}
Any idea how to fix this pealse ?
Could this be the same problem as the one mentioned (as an apple bug) by Lee Amtrong here :NSXMLParser Leaking
-(BOOL)fetchAndParseRss{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
//To suppress the leak in NSXMLParser
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
NSURL *url = [NSURL URLWithString:GALLERY_FEED];
BOOL success = NO;
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser setShouldProcessNamespaces:YES];
[parser setShouldReportNamespacePrefixes:YES];
[parser setShouldResolveExternalEntities:NO];
success = [parser parse];
[parser release];
[pool drain];
return success;
}
As found on this page, you can do the following to get rid of the leaks as well (I've found that you don't need the setMemoryCapacity or setDiskCapacity calls):
NSData *xml = [NSData
dataWithContentsOfURL: [NSURL
URLWithString:#"http://some-xml-url.com/my.xml"]];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xml];
I have developed my iPhone application and now I am testing it with instruments to find memory leakages .
I have my appDelegate class in which I am fetching data from web service and then parse it then store it in an array..
Here is my applicationDidFinishLaunching method :
UIApplication* app = [UIApplication sharedApplication];
app.networkActivityIndicatorVisible = YES;
serviceURL = [[NSUserDefaults standardUserDefaults] stringForKey:#"readOnly_key"];
NSLog(#"text = %#",serviceURL);
if(serviceURL == nil)
{
//We set the default values from the settings bundle.
//Get the bundle path
NSString *bPath = [[NSBundle mainBundle] bundlePath];
NSString *settingsPath = [bPath stringByAppendingPathComponent:#"Settings.bundle"];
NSString *plistFile = [settingsPath stringByAppendingPathComponent:#"Root.plist"];
NSDictionary *settingsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFile];
NSArray *preferencesArray = [settingsDictionary objectForKey:#"PreferenceSpecifiers"];
NSDictionary *item;
NSString *textEntry_Key;
NSString *readOnly_Key;
for(item in preferencesArray)
{
//Get the key of the item.
NSString *keyValue = [item objectForKey:#"Key"];
//Get the default value specified in the plist file.
id defaultValue = [item objectForKey:#"DefaultValue"];
if([keyValue isEqualToString:#"textEntry_key"]){
textEntry_Key = defaultValue;
}
NSLog(#"default value = %#",defaultValue);
if([keyValue isEqualToString:#"readOnly_key"])
readOnly_Key = defaultValue;
}
//Now that we have all the default values.
//We will create it here.
NSDictionary *appPrerfs = [NSDictionary dictionaryWithObjectsAndKeys:
textEntry_Key, #"textEntry_key",
readOnly_Key, #"readOnly_key",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:appPrerfs];
[[NSUserDefaults standardUserDefaults] synchronize];
}
NSURL *url5 = [[NSURL alloc] initWithString:#"http://192.168.0.150/Nirmal/Service.asmx/searchParameterList"];
//NSURL *url5 = [[NSURL alloc] initWithString:[NSString stringWithFormat:#"%#/Service.asmx/searchParameterList"]];
NSMutableURLRequest* request6=[NSMutableURLRequest requestWithURL:url5];
[request6 setHTTPMethod:#"POST"];
[request6 setTimeoutInterval:10];
//NSURLResponse *response6=nil;
// NSError *err6=nil;
//NSData *data6=[[NSURLConnection sendSynchronousRequest:request6 returningResponse:&response6 error:&err6] retain];
data2=[NSURLConnection sendSynchronousRequest:request6 returningResponse:nil error:nil];
if(data2 == nil)
{
UIAlertView* alert = [[UIAlertView alloc]initWithTitle:#"Alert" message:#"The network is not available.\n Please check the Internet connection." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
else
{
NSXMLParser *xmlParser5 = [[NSXMLParser alloc] initWithData:data2];
//Initialize the delegate.
SearchParameterDataParser *searchParameterDataParser = [[SearchParameterDataParser alloc] initSearchParameterDataParser];
//Set delegate
[xmlParser5 setDelegate:searchParameterDataParser];
//Start parsing the XML file.
#try {
// **the leakage line**
BOOL success1 = [xmlParser5 parse];
if(success1)
NSLog(#"No Errors");
else
NSLog(#"Error Error Error!!!");
}
#catch (NSException * e) {
NSLog(#"Exception in parsing %# %#",[e name], [e reason]);
}
//[xmlParser5 release];
[searchParameterDataParser release];
//[xmlParser5 release]; //leakage
}
[data2 release];
and this is my parser class :
#import "SearchParameterDataParser.h"
#import "AppDelegate.h"
#import "SearchClass.h"
#implementation SearchParameterDataParser
-(SearchParameterDataParser *)initSearchParameterDataParser{
[super init];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"SearchClass"]) {
[appDelegate.tempArray release];
appDelegate.tempArray = [[NSMutableArray alloc] init];
appDelegate.aSearchClass = [[SearchClass alloc]init];
}
NSLog(#"Processing Element: %#", elementName);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(!currentElementValue){
[currentElementValue release];
currentElementValue = [[NSMutableString alloc] initWithString:string];
}
else
[currentElementValue appendString:string];
NSLog(#"Processing Value: %#", currentElementValue);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"SearchClass"]){
[appDelegate.tempArray addObject:appDelegate.aSearchClass];
return;
}
else
[appDelegate.aSearchClass setValue:currentElementValue forKey:elementName];
// [currentElementValue release];
currentElementValue = nil;
}
- (void) dealloc {
[super dealloc];
[aSearchClass release];
[currentElementValue release];
//[self release];
}
#end
I have specified the leakage line in the code .
Can anyone tell me what is going wrong or how can I solve the memory leakage ???????
This is pretty messy, as a suggestion to clean things up a bit, try moving some memory management stuff to accessor methods - your code is littered with -release methods. ie,
instead of:-
if([elementName isEqualToString:#"SearchClass"]) {
[appDelegate.tempArray release];
appDelegate.tempArray = [[NSMutableArray alloc] init];
}
try:-
if([elementName isEqualToString:#"SearchClass"]) {
appDelegate.tempArray = [NSMutableArray array];
}
where
appDelegate has a method
- (void)setTempArray:(NSMutableArray *)value {
if(value!=tempArray){
[tempArray release];
tempArray = [value retain];
}
}
or you can use a #synthesized accessor method to save coding it yourself. As an aside tempArray is a terrible name for an instance variable. Also note that you are releasing the old tempArray each time you make a new one - when does the last instance get cleaned up?
This is still not great as your parser class should not access directly the instance variables in appDelegate. Vardiables tempArray and searchClass should be private, but that is off the point and more of a design issue.
Where does url5 get released?
What is this supposed to do?
if(!currentElementValue){
[currentElementValue release];
}
release currentElementValue if it doesn't exist?
[data2 release];
Did you retain data2?
- (void) dealloc {
[super dealloc];
[aSearchClass release];
[currentElementValue release];
//[self release];
}
i thought aSearchClass was an instance variable on appDelegate?
This might sound like nitpicking but it is much easier to track down leaks if make your code clear and you know exactly what is going on.
You need to release both url5 and xmlParser5, since you've allocated them using alloc.
You should also be wary of calling release on properties, since the standard setters created when you #synthesize an instance variable typically release the previous value of the variable before setting the new value.