Iphone NSXMLParser NSCFString内存泄漏

时间:2010-05-19 13:36:40

标签: iphone memory-leaks nsstring nsxmlparser

我正在构建一个解析RSS Feed的应用。在应用程序中,有两种不同类型的feed,它们的feed中的元素名称不同,因此我创建了一个NSXMLParser NSObject,它在解析之前获取每个feed的元素名称。这是我的代码:

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

}

当我创建类的实例时,我喜欢这样:

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

如果我使用泄漏工具运行应用程序,泄漏将指向NewsFeedParser.m中的[NSXMLNewsParser解析]调用。

以下是泄漏仪器的屏幕截图,其中NSCFStrings泄漏:

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

对于我的生活,我无法弄清楚这些泄漏的来源。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

didStartElement方法发生泄漏。我正在复制elementName而不释放它。

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

    }

}

答案 1 :(得分:0)

您可能还希望在将另一个NSMutableString分配到属性之前释放(如果需要)已分配的NSMutableString属性,如下所示:

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