开发者

iPhone: memory leak on autoreleased object?

开发者 https://www.devze.com 2023-01-20 08:52 出处:网络
开发者_JAVA技巧I am using the XMLParser class, which contains an array with XMLElement objects. The XMLElement is being allocated using the autorelease operation. However, for some reason I\'m getting

开发者_JAVA技巧I am using the XMLParser class, which contains an array with XMLElement objects. The XMLElement is being allocated using the autorelease operation. However, for some reason I'm getting a memory leak (using instruments) on this line:

self.currentElement = [[[XMLElement alloc] init] autorelease];

I'm also releasing the XMLParser object in the caller class. I've highlighted the "problematic" lines in the XMLParser source code below as comment.

I really tried everything to fix it, but unfortunately I do not understand why this is happening at all. Any help is appreciated!

Thank you very much!

// --- XMLElement

#import <Foundation/Foundation.h>


@interface XMLElement : NSObject {
     NSDictionary *attributes;
     NSMutableArray *children;
     NSString *textValue;
     NSString *tagName;
     XMLElement *parentElement;
}

-(id) init;
-(void) addChild:(XMLElement*) child;

@property(nonatomic, retain) NSDictionary *attributes;
@property(nonatomic, retain) NSMutableArray *children;
@property(nonatomic, retain) NSString *textValue;
@property(nonatomic, retain) NSString *tagName;
@property(nonatomic, retain) XMLElement *parentElement;

@end


#import "XMLElement.h"


@implementation XMLElement

@synthesize attributes, children, textValue, parentElement, tagName;

-(id)init {
     if(self = [super init]) {
          children = [[NSMutableArray alloc] init];
     }
     return self;
}

-(void) addChild:(XMLElement*) child{
     [self.children addObject:child];
}

- (void)dealloc {
     [attributes release];
     [children release];
     [textValue release];
     [tagName release];
     [parentElement release];
    [super dealloc];
}

@end





// --- XMLParser

#import <Foundation/Foundation.h>
#import "XMLElement.h"

@interface XMLParser : NSObject<NSXMLParserDelegate> {
     XMLElement *currentElement;
     XMLElement *currentParentElement;
     NSMutableString *currentElementValue;
}

- (BOOL)parseData: (NSData*) dataToParse;

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
     attributes:(NSDictionary *)attributeDict;

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;

@property (nonatomic, retain) XMLElement *currentParentElement;
@property (nonatomic, retain) XMLElement *currentElement;
@property (nonatomic, retain) NSMutableString *currentElementValue;

@end


#import "XMLParser.h"


@implementation XMLParser

@synthesize currentElementValue, currentElement, currentParentElement;

- (BOOL)parseData: (NSData*) dataToParse {

     NSXMLParser *parser = [[NSXMLParser alloc] initWithData:dataToParse];
     [parser setDelegate:self];
     BOOL success = [parser parse];
     [parser release];
     return success;
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
     attributes:(NSDictionary *)attributeDict{
     if(currentElement){
          self.currentParentElement = currentElement;
     }


     // ------------------------------------------------------------
     // Instruments is marking this line as source of the leak with 90%
     self.currentElement = [[[XMLElement alloc] init] autorelease];
     // --------

     currentElement.tagName = elementName;
     currentElement.attributes = attributeDict;
     currentElement.parentElement = self.currentParentElement;
     if(self.currentParentElement){
          [self.currentParentElement addChild:currentElement]; // and this one with 10%
     }

     self.currentElementValue = nil;
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
     if(!currentElement) {
          return;
     }

     if(currentElementValue == nil)
          self.currentElementValue = [NSMutableString stringWithString:string];
     else
          [currentElementValue appendString:string];
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
     if(currentElement == nil){
          if( currentParentElement.parentElement){
               self.currentParentElement = currentParentElement.parentElement;
          }
     }else{
          currentElement.textValue = currentElementValue; 
          [currentElementValue release];
          currentElementValue = nil;
          self.currentParentElement = currentElement.parentElement;
          currentElement = nil;
     }
}

- (void)dealloc {
     [currentParentElement release];
     [currentElement release];
    [super dealloc];
}

@end


You must release currentElement in your dealloc method in XMLParser.

It's created as autorelease but then assigned to a retain property, so you are actually retaining it once (which is good).

UPDATE: you should do self.currentElement = nil; when you are done with it, not currentElement = nil;.


This:

self.currentElement = [[[XMLElement alloc] init] autorelease];

retains currentElement (because the property is declared with retain).

Later, in parser:didEndElement:namespaceURI:qualifiedName:, you do this:

currentElement = nil;

which causes the leak because you are not releasing currentElement.


From what I see on this page, this is a documented apple bug. I have experienced the same problem in some of my apps...


Is your XMLParser being run on a background thread? If so, you need to create an NSAutoReleasePool for that thread in order for your [[[XMLElement alloc] init] autorelease] call to work.


HI guys. the reason is just one simple thing,

instead of

@property(nonatomic, retain) XMLElement *parentElement;

must be

@property(nonatomic, assign) XMLElement *parentElement;

also you need delete [parentElement release] from dealloc

reason is that you are creating cyclic referances. parent to child and chils to parent

and when you are realesing parser object the elements still ocurrs in memory with pointer xount > 0

0

精彩评论

暂无评论...
验证码 换一张
取 消