Memory Leak NSCFString Iphone NSXMLParser

I am creating an application that parses an rss feed. There are two different feed types in the application, with different names for the items in the feed, so I created an NSXMLParser NSObject that takes the name of the items in each feed before parsing. Here is my code:

NewsFeedParser.h

#import 


@interface NewsFeedParser: NSObject {
    NSInteger NewsSelectedCategory;
    NSXMLParser * NSXMLNewsParser;
    NSMutableArray * newsCategories;
    NSMutableDictionary * NewsItem;
    NSMutableString * NewsCurrentElement, * NewsCurrentElement1, * NewsCurrentElement2, * NewsCurrentElement3;
    NSString * NewsItemType, * NewsElement1, * NewsElement2, * NewsElement3;
    NSInteger NewsNumElements;
}

- (void) parseXMLFileAtURL: (NSString *) URL;
@property (nonatomic, retain) NSString * NewsItemType;
@property (nonatomic, retain) NSString * NewsElement1;
@property (nonatomic, retain) NSString * NewsElement2;
@property (nonatomic, retain) NSString * NewsElement3;
@property (nonatomic, retain) NSMutableArray * newsCategories;
@property (assign, nonatomic) NSInteger NewsNumElements;

@end

NewsFeedParser.m

#import "NewsFeedParser.h"


@implementation NewsFeedParser

@synthesize NewsItemType;
@synthesize NewsElement1;
@synthesize NewsElement2;
@synthesize NewsElement3;
@synthesize newsCategories;
@synthesize NewsNumElements;

- (void) parserDidStartDocument: (NSXMLParser *) parser {

}

- (void) parseXMLFileAtURL: (NSString *) URL
{   
    newsCategories = [[NSMutableArray alloc] init];

    URL = [URL stringByReplacingOccurrencesOfString: @ "" withString: @ ""];
    URL = [URL stringByReplacingOccurrencesOfString: @ "\ n" withString: @ ""];
    URL = [URL stringByReplacingOccurrencesOfString: @ "" withString: @ ""];

    // you must then convert the path to a proper NSURL or it won't work
    NSURL * xmlURL = [NSURL URLWithString: URL];

    // here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
    // this may be necessary only for the toolchain
    [[NSURLCache sharedURLCache] setMemoryCapacity: 0];
    [[NSURLCache sharedURLCache] setDiskCapacity: 0];
    NSXMLNewsParser = [[NSXMLParser alloc] initWithContentsOfURL: xmlURL];

    // Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
    [NSXMLNewsParser setDelegate: self];

    // Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
    [NSXMLNewsParser setShouldProcessNamespaces: NO];
    [NSXMLNewsParser setShouldReportNamespacePrefixes: NO];
    [NSXMLNewsParser setShouldResolveExternalEntities: NO];

    [NSXMLNewsParser parse];
    [NSXMLNewsParser release];
}


- (void) parser: (NSXMLParser *) parser parseErrorOccurred: (NSError *) parseError {
    NSString * errorString = [NSString stringWithFormat: @ "Unable to download story feed from web site (Error code% i)", [parseError code]];
    NSLog (@ "error parsing XML:% @", errorString);

    UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle: @ "Error loading content" message: errorString delegate: self cancelButtonTitle: @ "OK" otherButtonTitles: nil];
    [errorAlert show];
    [errorAlert release];
    [errorString release];
}


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

    NewsCurrentElement = [elementName copy];
    if ([elementName isEqualToString: NewsItemType]) 
    {
        // clear out our story item caches ...
        NewsItem = [[NSMutableDictionary alloc] init];
        NewsCurrentElement1 = [[NSMutableString alloc] init];
        NewsCurrentElement2 = [[NSMutableString alloc] init];
        if (NewsNumElements == 3)
        {
            NewsCurrentElement3 = [[NSMutableString alloc] init];
        }

    }

}

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

    if ([elementName isEqualToString: NewsItemType]) 
    {
        // save values ​​to an item, then store that item into the array ...
        [NewsItem setObject: NewsCurrentElement1 forKey: NewsElement1];

        [NewsItem setObject: NewsCurrentElement2 forKey: NewsElement2];

        if (NewsNumElements == 3)
        {
            [NewsItem setObject: NewsCurrentElement3 forKey: NewsElement3];
        }

        [newsCategories addObject: [[NewsItem copy] autorelease]];

        [NewsCurrentElement release];
        [NewsCurrentElement1 release];
        [NewsCurrentElement2 release];

        if (NewsNumElements == 3)
        {   
            [NewsCurrentElement3 release];  
        }

        [NewsItem release];

    }

}

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

    // NSLog (@ "found characters:% @", string);
    // save the characters for the current item ...
    if ([NewsCurrentElement isEqualToString: NewsElement1]) {
        [NewsCurrentElement1 appendString: string];
    } else if ([NewsCurrentElement isEqualToString: NewsElement2]) {
        [NewsCurrentElement2 appendString: string];
    } else if (NewsNumElements == 3 && [NewsCurrentElement isEqualToString: NewsElement3])
    {
        [NewsCurrentElement3 appendString: string];
    }

}

- (void) dealloc {
    [super dealloc];

    [newsCategories release];
    [NewsItemType release];
    [NewsElement1 release];
    [NewsElement2 release];
    [NewsElement3 release];

}

When I instantiate a class, I do this:

    NewsFeedParser * categoriesParser = [[NewsFeedParser alloc] init];

    if (newsCat == 0)
    {
        categoriesParser.NewsItemType = @ "article";
        categoriesParser.NewsElement1 = @ "category";
        categoriesParser.NewsElement2 = @ "catid";
    }
    else 
    {
        categoriesParser.NewsItemType = @ "article";
        categoriesParser.NewsElement1 = @ "category";
        categoriesParser.NewsElement2 = @ "feedUrl";
    }


    [categoriesParser parseXMLFileAtURL: feedUrl];
    newsCategories = [[NSMutableArray alloc] initWithArray: categoriesParser.newsCategories copyItems: YES];
    [self.tableView reloadData];
    [categoriesParser release];

If I run the application with the leak tool, the leaks point to the [NSXMLNewsParser parse] call in NewsFeedParser.m.

Here is a screenshot of the Leaks tool with the NSCFStrings leaked:

http://img139.imageshack.us/img139/3997/leaks.png

In my life I cannot understand where these leaks come from. Any help would be greatly appreciated.

+2


a source to share


2 answers


The leak occurred in the didStartElement method. I copied elementName without letting go.



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

    NewsCurrentElement = [[elementName copy] autorelease];
    if ([elementName isEqualToString: NewsItemType]) 
    {
        // clear out our story item caches ...
        NewsItem = [[NSMutableDictionary alloc] init];
        NewsCurrentElement1 = [[NSMutableString alloc] init];
        NewsCurrentElement2 = [[NSMutableString alloc] init];
        if (NewsNumElements == 3)
        {
            NewsCurrentElement3 = [[NSMutableString alloc] init];
        }

    }

}
0


a source


You can also free (if necessary) the highlighted properties NSMutableString

before highlighting another NSMutableString

in the property:



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

    if (NewsCurrentElement) {
        [NewsCurrentElement release], NewsCurrentElement = nil;
    }
    NewsCurrentElement = [[elementName copy] autorelease];

    if ([elementName isEqualToString:NewsItemType]) {
        // clear out our story item caches...
        if (NewsItem) {
            [NewsItem release], NewsItem = nil;
        }
        NewsItem = [[NSMutableDictionary alloc] init];

        if (NewsCurrentElement1) {
            [NewsCurrentElement1 release], NewsCurrentElement1 = nil;
        }
        NewsCurrentElement1 = [[NSMutableString alloc] init];

        if (NewsCurrentElement2) {
            [NewsCurrentElement2 release], NewsCurrentElement2 = nil;
        }
        NewsCurrentElement2 = [[NSMutableString alloc] init];

        if(NewsNumElements == 3) {
            if (NewsCurrentElement3) {
                [NewsCurrentElement3 release], NewsCurrentElement3 = nil;
            }
            NewsCurrentElement3 = [[NSMutableString alloc] init];
        }
    }
}

      

0


a source







All Articles