Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

Make your own iPhone apps
and run them live!
(free)

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 05-19-2010, 08:26 AM   #1 (permalink)
Registered Member
 
Join Date: May 2010
Posts: 35
atticusalien is on a distinguished road
Default [SOLVED] NSXMLParser NSCFString memory leak

I am building an app that parses an rss feed. In the app there are two different types of feeds with different names for the elements in the feed, so I have created an NSXMLParser NSObject that takes the name of the elements of each feed before parsing. Here is my code:

NewsFeedParser.h
Code:
#import <Foundation/Foundation.h>


@interface NewsFeedParser : NSObject {
	NSInteger NewsSelectedCategory;
	NSXMLParser *NSXMLNewsParser;
	NSMutableArray *newsCategories;
	NSMutableDictionary *NewsItem;
	NSMutableString *NewsCurrentElement, *NewsCurrentElement1, *NewsCurrentElement2, *NewsCurrentElement3;
	NSString *NewsItemType, *NewsElement1, *NewsElement2, *NewsElement3;
	NSInteger NewsNumElements;
}

- (void) parseXMLFileAtURL:(NSString *)URL;
@property(nonatomic, retain) NSString *NewsItemType;
@property(nonatomic, retain) NSString *NewsElement1;
@property(nonatomic, retain) NSString *NewsElement2;
@property(nonatomic, retain) NSString *NewsElement3;
@property(nonatomic, retain) NSMutableArray *newsCategories;
@property(assign, nonatomic) NSInteger NewsNumElements;

@end
NewsFeedParser.m
Code:
#import "NewsFeedParser.h"


@implementation NewsFeedParser

@synthesize NewsItemType;
@synthesize NewsElement1;
@synthesize NewsElement2;
@synthesize NewsElement3;
@synthesize newsCategories;
@synthesize NewsNumElements;

- (void)parserDidStartDocument:(NSXMLParser *)parser{
	
}

- (void)parseXMLFileAtURL:(NSString *)URL
{	
	newsCategories = [[NSMutableArray alloc] init];
	
	URL = [URL stringByReplacingOccurrencesOfString:@" " withString:@""];
	URL = [URL stringByReplacingOccurrencesOfString:@"\n" withString:@""];
	URL = [URL stringByReplacingOccurrencesOfString:@"	" withString:@""];
	
    //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
	[[NSURLCache sharedURLCache] setMemoryCapacity:0];
	[[NSURLCache sharedURLCache] setDiskCapacity:0];
    NSXMLNewsParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
	
	// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
    [NSXMLNewsParser setDelegate:self];
	
    // Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
    [NSXMLNewsParser setShouldProcessNamespaces:NO];
    [NSXMLNewsParser setShouldReportNamespacePrefixes:NO];
    [NSXMLNewsParser setShouldResolveExternalEntities:NO];
	
    [NSXMLNewsParser parse];
	[NSXMLNewsParser release];
}


- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
	NSString * errorString = [NSString stringWithFormat:@"Unable to download story feed from web site (Error code %i )", [parseError code]];
	NSLog(@"error parsing XML: %@", errorString);
	
	UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:@"Error loading content" message:errorString delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
	[errorAlert show];
	[errorAlert release];
	[errorString release];
}
 

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{			
	
	NewsCurrentElement = [elementName copy];
	if ([elementName isEqualToString:NewsItemType]) 
	{
		// clear out our story item caches...
		NewsItem = [[NSMutableDictionary alloc] init];
		NewsCurrentElement1 = [[NSMutableString alloc] init];
		NewsCurrentElement2 = [[NSMutableString alloc] init];
		if(NewsNumElements == 3)
		{
			NewsCurrentElement3 = [[NSMutableString alloc] init];
		}
		 
	}
	
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{     
	
	if ([elementName isEqualToString:NewsItemType]) 
	{
		// save values to an item, then store that item into the array...
		[NewsItem setObject:NewsCurrentElement1 forKey:NewsElement1];
		
		[NewsItem setObject:NewsCurrentElement2 forKey:NewsElement2];
		
		if(NewsNumElements == 3)
		{
			[NewsItem setObject:NewsCurrentElement3 forKey:NewsElement3];
		}
		
		[newsCategories addObject:[[NewsItem copy] autorelease]];
		
		[NewsCurrentElement release];
		[NewsCurrentElement1 release];
		[NewsCurrentElement2 release];
		
		if(NewsNumElements == 3)
		{	
			[NewsCurrentElement3 release];	
		}
		
		[NewsItem release];

	}
	
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
	
	//NSLog(@"found characters: %@", string);
	// save the characters for the current item...
	if ([NewsCurrentElement isEqualToString:NewsElement1]) {
		[NewsCurrentElement1 appendString:string];
	} else if ([NewsCurrentElement isEqualToString:NewsElement2]) {
		[NewsCurrentElement2 appendString:string];
	} else if (NewsNumElements == 3 && [NewsCurrentElement isEqualToString:NewsElement3])
	{
		[NewsCurrentElement3 appendString:string];
	}
	 
}

- (void)dealloc {
	[super dealloc];
	
	[newsCategories release];
	[NewsItemType release];
	[NewsElement1 release];
	[NewsElement2 release];
	[NewsElement3 release];

}
When I create an instance of the class I do like so:

Code:
	NewsFeedParser *categoriesParser = [[NewsFeedParser alloc] init];
	
	if(newsCat == 0)
	{
		categoriesParser.NewsItemType = @"article";
		categoriesParser.NewsElement1 = @"category";
		categoriesParser.NewsElement2 = @"catid";
	}
	else 
	{
		categoriesParser.NewsItemType = @"article";
		categoriesParser.NewsElement1 = @"category";
		categoriesParser.NewsElement2 = @"feedUrl";
	}
	
	
	[categoriesParser parseXMLFileAtURL:feedUrl];
	newsCategories = [[NSMutableArray alloc] initWithArray:categoriesParser.newsCategories copyItems:YES];
	[self.tableView reloadData];
	[categoriesParser release];
If I run the app with the leaks instrument, the leaks point to the [NSXMLNewsParser parse] call in the NewsFeedParser.m.

Here is a screen shot of the Leaks instrument with the NSCFStrings leaking:



For the life of me I can't figure out where these leaks are coming from. Any help would be greatly appreciated.

Last edited by atticusalien; 05-21-2010 at 07:57 PM.
atticusalien is offline   Reply With Quote
Old 05-20-2010, 03:57 PM   #2 (permalink)
Registered Member
 
Join Date: May 2010
Posts: 35
atticusalien is on a distinguished road
Default

bump*
atticusalien is offline   Reply With Quote
Old 05-20-2010, 04:54 PM   #3 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,990
BrianSlick has a spectacular aura about
Default

Rewrite it to use @properties for everything, then see where you are.
__________________
BriTer Ideas LLC - Professional iOS App Development. Available for hire.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
Definitive Guide To Properties | UITableView Series | Guide To Troubleshooting | Model Object Overview

Do you sit at a desk all day? Walk instead! Follow along with my treadmill desk adventures.
BrianSlick is offline   Reply With Quote
Old 05-20-2010, 06:13 PM   #4 (permalink)
Registered Member
 
Join Date: May 2010
Posts: 35
atticusalien is on a distinguished road
Default

Quote:
Rewrite it to use @properties for everything, then see where you are.
I'm new to Objective-C and Iphone development, so what would that do exactly? I thought you only needed to set a property for something that needs a getter and setter.
atticusalien is offline   Reply With Quote
Old 05-20-2010, 08:37 PM   #5 (permalink)
Registered Member
 
Join Date: Aug 2009
Location: Tasmania, Australia
Posts: 195
Son of a Beach is on a distinguished road
Default

Quote:
Originally Posted by atticusalien View Post
I'm new to Objective-C and Iphone development, so what would that do exactly? I thought you only needed to set a property for something that needs a getter and setter.
You don't NEED to use properties, but it can simplify memory management. Ie, if you use a property correctly, it will ALWAYS release the old value when it sets a new value and never leak the old value.

With all the callbacks used in NSXMLParsers, it can be a bit tricky to follow what is going on, and which order things are being called in. It can be simpler to use properties in any situation where tracking retains and releases would otherwise be a bit difficult, even if the properties don't need to be accessed by any other objects.
Son of a Beach is offline   Reply With Quote
Old 05-20-2010, 08:42 PM   #6 (permalink)
Registered Member
 
Join Date: Aug 2009
Location: Tasmania, Australia
Posts: 195
Son of a Beach is on a distinguished road
Default

Looks like "newsCategories" is defined as a property, but you're assigning to it using:
Code:
newsCategories = [[NSMutableArray alloc] init];
I think your supposed to assign properties using the "." notation (except in init methods, or where you can be absolutely sure it's not got a memory-allocated value already), even when available as a local variable:
Code:
self.newsCategories = [[NSMutableArray alloc] init];
I could be wrong though... I'm a bit new to properties myself.

Last edited by Son of a Beach; 05-20-2010 at 09:32 PM.
Son of a Beach is offline   Reply With Quote
Old 05-20-2010, 09:23 PM   #7 (permalink)
Emphasizing Fundamentals
 
BrianSlick's Avatar
 
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,990
BrianSlick has a spectacular aura about
Default

See the properties link in my signature for more info.
__________________
BriTer Ideas LLC - Professional iOS App Development. Available for hire.

SlickShopper 2 | Free NSLog utility | Leave a PayPal donation.

Are you a newbie? Things you should read:
Definitive Guide To Properties | UITableView Series | Guide To Troubleshooting | Model Object Overview

Do you sit at a desk all day? Walk instead! Follow along with my treadmill desk adventures.
BrianSlick is offline   Reply With Quote
Old 05-21-2010, 05:26 PM   #8 (permalink)
Registered Member
 
Join Date: May 2010
Posts: 35
atticusalien is on a distinguished road
Default

The leak was happening in the didStartElement method. I was copying a string without releasing it.

Code:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{			
	
	NewsCurrentElement = [[elementName copy] autorelease];
	if ([elementName isEqualToString:NewsItemType]) 
	{
		// clear out our story item caches...
		NewsItem = [[NSMutableDictionary alloc] init];
		NewsCurrentElement1 = [[NSMutableString alloc] init];
		NewsCurrentElement2 = [[NSMutableString alloc] init];
		if(NewsNumElements == 3)
		{
			NewsCurrentElement3 = [[NSMutableString alloc] init];
		}
		 
	}
	
}
atticusalien is offline   Reply With Quote
Reply

Bookmarks

Tags
leak, memory, memory leak, nscfstring, nsxmlparser

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 309
9 members and 300 guests
Abidullah, ajay123123, Fstuff, guusleijsten, HemiMG, newDev, pkIDSF, Sami Gh, Steven.C
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,648
Threads: 94,113
Posts: 402,877
Top Poster: BrianSlick (7,990)
Welcome to our newest member, brandon6031
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 07:48 PM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0