Reputation: 1885
Below is the @interface for an MREntitiesConverter object I use to strip all html tags from a string using an NSXMLParser.
@interface MREntitiesConverter : NSObject {
NSMutableString* resultString;
NSString* xmlStr;
NSData *data;
NSXMLParser* xmlParser;
}
@property (nonatomic, retain) NSMutableString* resultString;
- (NSString*)convertEntitiesInString:(NSString*)s;
@end
And this is the implementation:
@implementation MREntitiesConverter
@synthesize resultString;
- (id)init
{
if([super init]) {
self.resultString = [NSMutableString string];
}
return self;
}
- (NSString*)convertEntitiesInString:(NSString*)s {
xmlStr = [NSString stringWithFormat:@"<data>%@</data>", s];
data = [xmlStr dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
xmlParser = [[NSXMLParser alloc] initWithData:data];
[xmlParser setDelegate:self];
[xmlParser parse];
return [resultString autorelease];
}
- (void)dealloc {
[data release];
//I want to release xmlParser here but it crashes the app
[super dealloc];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)s {
[self.resultString appendString:s];
}
@end
If I release xmlParser
in the dealloc method I am crashing my app but without releasing I am quite obviously leaking memory.
I am new to Instruments and trying to get the hang of optimising this app. Any help you can offer on this particular issue will likely help me solve other memory issues in my app.
Yours in frustrated anticipation: ) Oisin
Upvotes: 2
Views: 1299
Reputation: 1885
Based on some really helpful sugestions here, this is the latest version of my code, which does not appear to leak memory:
@interface MREntitiesConverter : NSObject {
NSMutableString* resultString;
}
@property (nonatomic, retain) NSMutableString* resultString;
- (NSString*)convertEntitiesInString:(NSString*)s;
@end
@implementation MREntitiesConverter
@synthesize resultString;
- (NSString*)convertEntitiesInString:(NSString*)s {
self.resultString = [NSMutableString string];
NSString* xmlStr = [NSString stringWithFormat:@"<d>%@</d>", s];
NSData *data = [xmlStr dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSXMLParser* xmlParse = [[NSXMLParser alloc] initWithData:data];
[xmlParse setDelegate:self];
[xmlParse parse];
[xmlParse release];
return [self.resultString autorelease];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)s {
[resultString appendString:s];
}
@end
The only oddity is that if I trace the retainCount
of resultString
just prior to returning it I get a count of 2
where I would have expected it to be 1
. Any idea why?
Upvotes: 0
Reputation: 969
I believe it is resultString, which cause crash. This is NSMutableString and you've not allocated any memory for this. Also release xmlParser in convertEntitiesInString before return [resultString autorelease];
Upvotes: 0
Reputation: 53669
Both your class and NSXMLParser are releasing data, which causes your current crash. The only member should be resultString. You should initialize resultString in convertEntitiesInString: not init, so the same instance could be used more than once. You should return either self.resultString or [[resultString retain] autorelease] from convert, because what you currently do will cause a double release later if you release resultString in dealloc as you should. You should use resultString directly in parser:foundCharacters: instead of self.resultString which is a method call.
Upvotes: 3
Reputation: 27601
While the other two comments are correct (you're forgetting to release
the parser in the method you alloc
it, which is a memory leak), I bet it's crashing specifically because you set your MREntitiesConverter
class as the delegate
for the parser.
Upvotes: 0
Reputation: 3361
Are you sure [xmlParser release] is crashing the application in dealloc? I see you have [data release] in dealloc and I can't see a statement where you have used alloc to allocate memory to it.
Upvotes: 2
Reputation: 410662
I don't see xmlParser
being used outside of convertEntitiesInString:
. You could make xmlParser
local to that method (not an instance variable) and release it when you're done with it in that method, before the return [resultString autorelease]
line.
Upvotes: 2