IPHONE: NSXMLParser leak NSPlaceholderString

This is probably the most annoying leak I've every faced. With the NSXMLParser, I was getting these crazy 16 byte NSCFString leaks. The leaks traced back to [NSXMLParser parse], caused by NSPlaceholderString initWithBytes/initWithString.

I believe this is caused by the [parser:foundcharacters] method. Generally, the xml document being parsed has a bunch of \t and \n characters. It would appear these are the culprit. I got rid of the parse leaks by doing the following:

- (void)parser:(NSXMLParser*)parser foundCharacters:(NSString*)cdata {
NSString* tmp = [cdata stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if(curr && tmp && [tmp length] > 0) {
curr.content:tmp;
}
}

Where curr is the variable saving the cdata 'found characters'.

5 comments:

Unknown said...

hi,
i'm a bit puzzled by your solution, are you overriding a parser function? but curr is not public/protected data.

how can i use your solution?

best regards

Chris

Dev Culture said...

typically, a 'good looking' xml file will look something like

<parent>\r\n
<child>content\r\n
</child>\r\n
</parent>

(where \r\n are return characters)

i believe these are the causes for the leaks. not sure what's really going on the in background.

to solve this you can either do:

1. combine everything to one line:
<parent><child>content</child></parent>

or

2. use my suggested solution to remove the 'white space characters' (\r\n) from the 'content'

you can email me directly at wdyu2002@yahoo.com to further discuss this issue.

Dev Culture said...

actually i just realized my posted solution is rather incomplete.

i probably need to further explain how my code works:

as you probably know, the foundCharacter method is for finding 'content' in-between xml tags.

ie. <child>content</child>

for my xml parser, i store ALL 'content' text into an array. I had not considered that in my 'good-looking' xml all of the \t (tab) and \r (return) characters are actually being stored as well. as such, I wasn't freeing them correctly.

since in most cases you probably didn't intend for \t\r\n characters to be saved for later use, I used the stringByTrimmingCharactersInSet (remove white spaces) method to figure out whether or not I really want to save the 'content' text.

once I stopped storing them, the leaks disappeared.

sorry if this doesn't help you in your case. i was half asleep when i posted the solution and didn't even notice the solution only applies to my parser code.

Unknown said...

i see, thanks anyway. My problem was that i read from a tcp socket continiously so the autorelease pool is never freed:

while (data = [self readfromsocket]) {

[parser parse:data];
}

what should have been;

while (data = [self readfromsocket]) {

AutoreleasePool *pool = [[alloc etc]
[parser parse:data];
[pool release];
}

the parser never leaked, it just never came arround to freeing the data.

thanks anyway

Chris

Unknown said...

if(curr && tmp && [tmp length] > 0) {
curr.content:tmp;
}

What exactly do these two lines do? What kind of variable has .content? I'm not sure how to add this into my code.