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 01-11-2011, 08:45 AM   #1 (permalink)
Registered Member
 
Join Date: Jan 2011
Posts: 10
mikesowerbutts is on a distinguished road
Angry i cant see why this is leaking memory!

Hi All,
I have been working on a class to parse xml for ages now - I had a bug in my original class, so I re-wrote it (as it was a flawed approach anyway) to be more efficient, unfortunately I have now encountered issues when running on my ipad (as it runs fine in the simulator) which I believe are caused by the app leaking memory. The only thing I have changed since this problem started was my WSXMLObject class. So i guess it must be that.
I am getting "The debugger exited with status 0" which I understand means that the app has closed becuase its using too much memory.
The code below is about 60% of the .m file for my WSXMLObject class - had to remove some of the methods becuase there was a character limit on the post!

Code:
#import "WSXMLObject.h"
#import "WSKVPair.h"

@implementation WSXMLObject
@synthesize name, outerXML, innerXML, children, attributes, parent, startTag, endTag, xStart;

-(id)init:(NSString *)theXML
{
	@try {
		//Setup Vars
		children = [[NSMutableDictionary alloc] init];
		attributes = [[NSMutableDictionary alloc] init];
		if(![theXML isEqualToString:@""]){
			[self Build:theXML];
			self.outerXML = [theXML substringToIndex:xStart];
			if([startTag rangeOfString:@"/>"].location != NSNotFound)
			{
				self.outerXML = startTag;
				self.innerXML = [[[NSString alloc] initWithString:@""] autorelease];
			}
			else{
				self.innerXML = [outerXML substringWithRange:NSMakeRange(startTag.length, outerXML.length - (startTag.length + endTag.length))];
			}
		}
		//[theXML release];
	}
	@catch (NSException * e) {
		NSLog(@"ERROR when Parsing XML: %@, Error: %@", theXML, e.reason);
	}
	
	return self;
}

-(void)Build:(NSString *)tXML{
	BOOL debug = NO;
	int cStart = 0;
	int dupCounter = 0;
	NSString *nextTag;
	int ntLoc;
	self.startTag = [self BuildStartTag:tXML];
	[self BuildAttributes];
	self.name = [self BuildName:startTag];
	self.endTag = [self BuildEndTag:name searchString:tXML];
	BOOL ok = YES;
	while(ok){
		ntLoc = [self GetLocationOfNextTag:[tXML substringFromIndex:startTag.length]];
		NSRange locRan = [tXML rangeOfString:@"<" options:nil range:NSMakeRange(startTag.length + cStart, tXML.length - (startTag.length + cStart))];
		NSRange lenRan = NSMakeRange(locRan.location, tXML.length - locRan.location);
		NSRange ntRange = NSMakeRange(locRan.location, ([tXML rangeOfString:@">" options:nil range:lenRan].location - lenRan.location) + 1);
		nextTag = [tXML substringWithRange:ntRange];
		if([nextTag isEqualToString:endTag] || [startTag rangeOfString:@"/>"].location != NSNotFound){
			int inc = 0;
			for(int i = 0; i < [children count]; i++){
				WSXMLObject *o = [self GetByIndex:i];
				inc += o.outerXML.length;
			}
			if(inc == 0){
				inc = [tXML rangeOfString:endTag].location;
			}
			else{
				inc += startTag.length;
			}
			cStart = inc + endTag.length;
			ok = NO;
		}
		else if(ntLoc != -1){
			NSString *childXML = [tXML substringFromIndex:startTag.length + cStart];
			WSXMLObject *childObj = [[WSXMLObject alloc] init:childXML];
			childObj.parent = self;
			if([children valueForKey:childObj.name] != nil){
				NSString *c = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%d", dupCounter]];
				dupCounter++;
				childObj.name = [childObj.name stringByAppendingFormat:c];
				[c release];
			}
			[children setObject:childObj forKey:childObj.name];
			[childObj release];
			childObj = nil;
			
			int inc = 0;
			int cnt = children.count;
			for(int i = 0; i < cnt; i++){
				WSXMLObject *o = [self GetByIndex:i];
				inc += o.outerXML.length;
			}
			cStart = inc;
		}
	}
	xStart = cStart;
}
-(void)AddChild:(WSXMLObject *)childObj{
	int dupCounter = 0;
	while([children valueForKey:childObj.name] != nil){
		NSString *c = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%d", dupCounter]];
		dupCounter++;
		childObj.name = [childObj.name stringByAppendingFormat:c];
		[c release];
	}
	[children setObject:childObj forKey:childObj.name];
	NSMutableString *oStr = [[NSMutableString alloc] init];
	for(int i = 0; i < [self.children count]; i++){
		[oStr appendString:[[[self.children allValues] objectAtIndex:i] outerXML]];
	}
	self.outerXML = [NSString stringWithFormat:@"%@%@%@", startTag, oStr, endTag];
	self.innerXML = oStr;
	[oStr release];
	[childObj release];
}
-(id)Get:(NSString *)objName
{
	NSArray *pathParts = [objName componentsSeparatedByString:@"/"];
	NSArray *keys = [self.children allKeys];
	if([keys containsObject:[pathParts objectAtIndex:0]])
	{
		if([pathParts count] > 1)
		{
			WSXMLObject *obj = self;
			WSXMLObject *obj2;
			for(NSString *part in pathParts)
			{
				if([part intValue] != 0 || [part isEqualToString:@"0"])
				{
					obj2 = [obj GetByIndex:[part intValue]];		
				}
				else
				{
					obj2 = [obj.children valueForKey:part];
				}
				obj = obj2;
			}
			return obj;
		}
		else
		{
			return [children valueForKey:[pathParts objectAtIndex:0]];
		}
	}
	else
	{
		return nil;	
	}
}
-(id)GetByIndex:(NSUInteger)idx
{
	WSXMLObject *obj = (WSXMLObject *)[[[children allValues] objectAtIndex:idx] retain];
	return [obj autorelease];
}
-(NSString *)GetAttribute:(NSString *)attName
{
	NSArray *keys = [attributes allKeys];
	if([keys containsObject:attName])
	{
		return [attributes valueForKey:attName];
	}
	else
	{
		return nil;	
	}
}
-(WSKVPair *)GetAttributeKVPair:(NSString *)attName
{
	NSArray *keys = [attributes allKeys];
	if([keys containsObject:attName])
	{
		// HERE
		NSString *val = [[attributes valueForKey:attName] retain];
		WSKVPair *kvp = [[[WSKVPair alloc] initWithKeyValue:attName aValue:val] autorelease];
		[val release];
		[attName release];
		return kvp;
	}
	else
	{
		return nil;	
	}
}
-(void)SetAttribute:(NSString *)attName newAttValue:(NSString *)newValue
{
	NSArray *keys = [attributes allKeys];
	if([keys containsObject:attName]){
		[attributes setValue:newValue forKey:attName];
	}
}
-(NSString *)GetAttributeByIndex:(NSUInteger)idx
{
	NSArray *keys = [attributes allKeys];
	if(idx < [keys count])
	{
		return [attributes valueForKey:[keys objectAtIndex:idx]];
	}
	else
	{
		return nil;	
	}
}
-(NSMutableArray *)GetChildAttributesByName:(NSString *)attName
{
	NSMutableArray *vals = [[[NSMutableArray alloc] initWithCapacity:attributes.count] autorelease];
	for(WSXMLObject *obj in [children allValues])
	{
		NSString *att = [obj GetAttribute:attName];
		[vals addObject:att];
	}
	return vals;
}
-(WSXMLObject *)GetByAttributeValue:(NSString *)attName attValue:(NSString *)attValue{
	for(int i = 0; i < [children count]; i++){
		WSXMLObject *obj = [[children allValues] objectAtIndex:i];
		WSKVPair *attPair = [obj GetAttributeKVPair:attName];
		if(attPair != nil){
			if(attPair.value != nil && [attPair.value isEqualToString:attValue]){
				return obj;
			}
		}
		//[attPair release];
	}
	return nil;
}
-(void)dealloc
{
	[name release];
	[innerXML release];
	[children release];
	[attributes release];
	[parent release];
	[outerXML release];
	[startTag release];
	[endTag release];
	name = nil;
	innerXML = nil;
	children = nil;
	attributes = nil;
	parent = nil;
	outerXML = nil;
	startTag = nil;
	endTag = nil;
	[super dealloc];
}

@end
When I try to run it though Instruments "Leaks" on either the simulator, or my ipad, it just gives a black screen for a while, then crashes. But if i run it "Normall" i.e. not in Instruments etc. it runs fine until I get the "The debugger exited with status 0" message in the debug window.
I think it must be leaking in the Build function primarily as that basically does all the work, namely the outerXML string property leaking and maybe the children dictionary property too, but im not sure how to change it to stop the leak
Im really stuck on this!

Thanks,
Mike
mikesowerbutts is offline   Reply With Quote
Old 01-11-2011, 10:44 AM   #2 (permalink)
Reading the Documentation
 
baja_yu's Avatar
 
Join Date: Sep 2010
Location: 45.255019,19.844908
Posts: 5,414
baja_yu has a spectacular aura about
Default

How are 'children' and 'attributes' properties declared? If they are (retain) properties than these two lines will retain them twice

children = [[NSMutableDictionary alloc] init];
attributes = [[NSMutableDictionary alloc] init];
baja_yu is offline   Reply With Quote
Old 01-11-2011, 10:50 AM   #3 (permalink)
Senior Member
iPhone Dev SDK Supporter
 
Join Date: Aug 2008
Location: Memphis, TN, USA
Age: 24
Posts: 3,983
smithdale87 is on a distinguished road
Send a message via AIM to smithdale87
Default

Quote:
How are 'children' and 'attributes' properties declared? If they are (retain) properties than these two lines will retain them twice

children = [[NSMutableDictionary alloc] init];
attributes = [[NSMutableDictionary alloc] init];
That is incorrect.

If it were stated as self.children = ... and self.attributes = ... AND your properties were declared as "retain" THEN it would be a memory leak. As you have it here, there is no leaking.
smithdale87 is offline   Reply With Quote
Old 01-11-2011, 10:52 AM   #4 (permalink)
Registered Member
 
Join Date: Jan 2011
Posts: 10
mikesowerbutts is on a distinguished road
Default

Hi,

any ideas why my app crashed specifically when parsing xml then? like i said it only crashes on an ipad, not the simulator.

Thanks,

Mike
mikesowerbutts is offline   Reply With Quote
Old 01-11-2011, 10:58 AM   #5 (permalink)
Reading the Documentation
 
baja_yu's Avatar
 
Join Date: Sep 2010
Location: 45.255019,19.844908
Posts: 5,414
baja_yu has a spectacular aura about
Default

I stand corrected.
baja_yu is offline   Reply With Quote
Old 01-11-2011, 11:05 AM   #6 (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

Not leaks, but...

Code:
self.innerXML = [[[NSString alloc] initWithString:@""] autorelease];
...
NSString *c = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%d", dupCounter]];
...
NSString *c = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%d", dupCounter]];
...Ok, people! Seriously, stop formatting strings as strings

Your init method should involve super. And you really should call it initWithXML: or something like that to avoid confusion.

I'm not seeing any leaks at a glance, but there is a lot of code there that I'm not going to comb through.
__________________
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
Reply

Bookmarks

Tags
memory leak, property, xml parser

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: 361
9 members and 352 guests
7twenty7, blueorb, iAppDeveloper, iGamesDev, Mah6447, Morrisone, mottdog, sacha1996, Touchmint
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,667
Threads: 94,120
Posts: 402,898
Top Poster: BrianSlick (7,990)
Welcome to our newest member, host number one
Powered by vBadvanced CMPS v3.1.0

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