Iphone NSXMLParser NSCFString 内存泄漏

Posted

技术标签:

【中文标题】Iphone NSXMLParser NSCFString 内存泄漏【英文标题】:Iphone NSXMLParser NSCFString memory leak 【发布时间】:2011-02-21 09:33:09 【问题描述】:

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

NewsFeedParser.h

#进口 @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, 保留) NSString *NewsItemType; @property(nonatomic, 保留) NSString *NewsElement1; @property(nonatomic, 保留) NSString *NewsElement2; @property(nonatomic, 保留) NSString *NewsElement3; @property(nonatomic, 保留) NSMutableArray *newsCategories; @property(assign, nonatomic) NSInteger NewsNumElements; @结尾

NewsFeedParser.m

#import "NewsFeedParser.h" @implementation NewsFeedParser @synthesize NewsItemType; @synthesize NewsElement1; @synthesize NewsElement2; @synthesize NewsElement3; @synthesize 新闻类别; @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:@""]; //然后你必须将路径转换为正确的 NSURL 否则它将不起作用 NSURL *xmlURL = [NSURL URLWithString:URL]; // 这里,由于某种原因,你必须在尝试分配 NSXMLParser 时使用 NSClassFromString,否则你会得到一个 object not found 错误 // 这可能仅对工具链是必需的 [[NSURLCache sharedURLCache] setMemoryCapacity:0]; [[NSURLCache sharedURLCache] setDiskCapacity:0]; NSXMLNewsParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL]; // 将 self 设置为解析器的委托,以便接收解析器委托方法回调。 [NSXMLNewsParser setDelegate:self]; // 根据您正在解析的 XML 文档,您可能希望启用 NSXMLParser 的这些功能。 [NSXMLNewsParser setShouldProcessNamespaces:NO]; [NSXMLNewsParser setShouldReportNamespacePrefixes:NO]; [NSXMLNewsParser setShouldResolveExternalEntities:NO]; [NSXMLNewsParser 解析]; [NSXMLNewsParser 发布]; - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError NSString * errorString = [NSString stringWithFormat:@"无法从网站下载故事源(错误代码 %i )", [parseError code]]; NSLog(@"解析 XML 时出错:%@", errorString); UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:@"加载内容时出错" message:errorString delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [错误警报显示]; [错误警报发布]; [错误字符串释放]; - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURIqualifiedName:(NSString *)qName 属性:(NSDictionary *)attributeDict NewsCurrentElement = [元素名称副本]; if ([elementName isEqualToString:NewsItemType]) // 清除我们的故事项目缓存... NewsItem = [[NSMutableDictionary alloc] init]; NewsCurrentElement1 = [[NSMutableString alloc] init]; NewsCurrentElement2 = [[NSMutableString alloc] init]; 如果(NewsNumElements == 3) NewsCurrentElement3 = [[NSMutableString alloc] init]; - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURIqualifiedName:(NSString *)qName if ([elementName isEqualToString:NewsItemType]) // 将值保存到一个项目中,然后将该项目存储到数组中... [NewsItem setObject:NewsCurrentElement1 forKey:NewsElement1]; [NewsItem setObject:NewsCurrentElement2 forKey:NewsElement2]; 如果(NewsNumElements == 3) [NewsItem setObject:NewsCurrentElement3 forKey:NewsElement3]; [newsCategories addObject:[[NewsItem copy] autorelease]]; [NewsCurrentElement 发布]; [NewsCurrentElement1 发布]; [NewsCurrentElement2 发布]; 如果(NewsNumElements == 3) [NewsCurrentElement3 发布]; [新闻项目发布]; - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string //NSLog(@"找到的字符:%@", string); // 保存当前项目的字符... 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]; - (无效)dealloc [超级释放]; 【新闻分类发布】; [NewsItemType 发布]; [NewsElement1 发布]; [NewsElement2 发布]; [NewsElement3 发布];

当我创建类的实例时,我会这样做:

NewsFeedParser *categoriesParser = [[NewsFeedParser alloc] init]; 如果(newsCat == 0) categoriesParser.NewsItemType = @"article"; categoriesParser.NewsElement1 = @"category"; categoriesParser.NewsElement2 = @"catid"; 别的 categoriesParser.NewsItemType = @"article"; categoriesParser.NewsElement1 = @"category"; categoriesParser.NewsElement2 = @"feedUrl"; [categoriesParser parseXMLFileAtURL:feedUrl]; newsCategories = [[NSMutableArray alloc] initWithArray:categoriesParser.newsCategories copyItems:YES]; [self.tableView reloadData]; [类别解析器发布];

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

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

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

在我的一生中,我无法弄清楚这些泄漏是从哪里来的。任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

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

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURIqualifiedName:(NSString *)qName 属性:(NSDictionary *)attributeDict NewsCurrentElement = [[elementName copy] autorelease]; if ([elementName isEqualToString:NewsItemType]) // 清除我们的故事项目缓存... NewsItem = [[NSMutableDictionary alloc] init]; NewsCurrentElement1 = [[NSMutableString alloc] init]; NewsCurrentElement2 = [[NSMutableString alloc] init]; 如果(NewsNumElements == 3) NewsCurrentElement3 = [[NSMutableString alloc] init];

【讨论】:

【参考方案2】:

您可能还想释放(如有必要)分配的 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];
        
    

【讨论】:

以上是关于Iphone NSXMLParser NSCFString 内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

iOS - 关于 NSXMLParser 和 libxml2 的区别

iPhone解析XML数据,标签未出现

从次线程访问实例属性(iPhone-SDK)

如何解析此 xml 并检索 iPhone 中的数据 [重复]

在后台线程中使用 MagicalRecord 和 NSXMLParser

iOS - OC - XML 解析 - NSXMLParser