01-11-2011, 08:45 AM
#1 (permalink )
Registered Member
Join Date: Jan 2011
Posts: 10
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
01-11-2011, 10:44 AM
#2 (permalink )
Reading the Documentation
Join Date: Sep 2010
Location: 45.255019,19.844908
Posts: 5,414
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];
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
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.
01-11-2011, 10:52 AM
#4 (permalink )
Registered Member
Join Date: Jan 2011
Posts: 10
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
01-11-2011, 10:58 AM
#5 (permalink )
Reading the Documentation
Join Date: Sep 2010
Location: 45.255019,19.844908
Posts: 5,414
I stand corrected.
01-11-2011, 11:05 AM
#6 (permalink )
Emphasizing Fundamentals
Join Date: Jul 2009
Location: NoVA / DC Area
Age: 36
Posts: 7,990
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.
Thread Tools
Display Modes
Linear Mode
Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
» 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