开发者

Iphone NSXMLParser NSCFString memory leak

I am building an app that parses an rss feed. In the app there are two different types of feeds with different names for the elements in the feed, so I have created an NSXMLParser NSObject that takes the name of the elements of 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 stri开发者_Go百科ngByReplacingOccurrencesOfString:@" " 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 create an instance of the class I do like so:

    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 app with the leaks instrument, the leaks point to the [NSXMLNewsParser parse] call in the NewsFeedParser.m.

Here is a screen shot of the Leaks instrument with the NSCFStrings leaking:

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

For the life of me I can't figure out where these leaks are coming from. Any help would be greatly appreciated.


The leak occurred in the didStartElement method. I was copying elementName without releasing it.

- (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];
        }

    }

}


You might also want to release (if necessary) the allocated NSMutableString properties before allocating another NSMutableString into the property like so:

- (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

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜