Я анализирую XML-файл, используя пользовательский класс, который создает и использует NSXMLParser. При первом вызове все в порядке, но при втором, третьем и последующих вызовах инструменты показывают десятки утечек памяти в определенных строках внутри функций didEndElement, didEndElement и foundCharacters.
Я прогуглил это и нашел, что у некоторых людей есть эта проблема, но я не нашел ничего, что могло бы действительно помочь мне.
Мой класс Parser выглядит так:
parser.h
@interface XMLParser : NSObject {
NSMutableArray *data;
NSMutableString *currentValue;
NSArray *xml;
NSMutableArray *videos;
NSMutableArray *photos;
NSXMLParser *parser;
NSURLConnection *feedConnection;
NSMutableData *downloadedData;
Content *content;
Video *video;
BOOL nowPhoto;
BOOL nowVideo;
BOOL finished;
BOOL webTV;
}
-(void)parseXML:(NSURL*)xmlURL;
-(int)getCount;
-(NSArray*)getData;
//- (void)handleError:(NSError *)error;
//@property(nonatomic, retain) NSMutableString *currentValue;
@property(nonatomic, retain) NSURLConnection *feedConnection;
@property(nonatomic, retain) NSMutableData *downloadedData;
@property(nonatomic, retain) NSArray *xml;
@property(nonatomic, retain) NSXMLParser *parser;
@property(nonatomic, retain) NSMutableArray *data;
@property(nonatomic, retain) NSMutableArray *photos;
@property(nonatomic, retain) NSMutableArray *videos;
@property(nonatomic, retain) Content *content;
@property(nonatomic, retain) Video *video;
@property(nonatomic) BOOL finished;
@property(nonatomic) BOOL nowPhoto;
@property(nonatomic) BOOL nowVideo;
@property(nonatomic) BOOL webTV;
@end
Parser.m
#import "Content.h"
#import "Video.h"
#import "Parser.h"
#import <CFNetwork/CFNetwork.h>
@implementation XMLParser
@synthesize xml, parser, finished, nowPhoto, nowVideo, webTV;
@synthesize feedConnection, downloadedData, data, content, photos, videos, video;
-(void)parseXML:(NSURL*)xmlURL {
/*
NSURLRequest *req = [NSURLRequest requestWithURL:xmlURL];
self.feedConnection = [[[NSURLConnection alloc] initWithRequest:req delegate:self] autorelease];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
*/
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
NSXMLParser *feedParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
//NSXMLParser *feedParser = [[NSXMLParser alloc] initWithData:theXML];
[self setParser:feedParser];
[feedParser release];
[[self parser] setDelegate:self];
[[self parser] setShouldResolveExternalEntities:YES];
[[self parser] parse];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if ([elementName isEqualToString:@"articles"]) {
self.finished = NO;
self.nowPhoto = NO;
self.nowVideo = NO;
self.webTV = NO;
if (!data) {
NSMutableArray *tmp = [[NSMutableArray alloc] init];
[self setData:tmp];
[tmp release];
return ;
}
}
if ([elementName isEqualToString:@"WebTV"]) {
self.finished = NO;
self.nowPhoto = NO;
self.nowVideo = NO;
self.webTV = YES;
if (!data) {
NSMutableArray *tmp = [[NSMutableArray alloc] init];
[self setData:tmp];
[tmp release];
return ;
}
}
if ([elementName isEqualToString:@"photos"]) {
if (!photos) {
NSMutableArray *tmp = [[NSMutableArray alloc] init];
[self setPhotos:tmp];
[tmp release];
return;
}
}
if ([elementName isEqualToString:@"videos"]) {
if (!videos) {
NSMutableArray *tmp = [[NSMutableArray alloc] init];
[self setVideos:tmp];
[tmp release];
return;
}
}
if ([elementName isEqualToString:@"photo"]) {
self.nowPhoto = YES;
self.nowVideo = NO;
}
if ([elementName isEqualToString:@"video"]) {
self.nowPhoto = NO;
self.nowVideo = YES;
}
if ([elementName isEqualToString:@"WebTVItem"]) {
if (!video) {
Video *tmp = [[Video alloc] init];
[self setVideo:tmp];
[tmp release];
}
NSString *videoId = [attributeDict objectForKey:@"id"];
[[self video] setVideoId:[videoId intValue]];
}
if ([elementName isEqualToString:@"article"]) {
if (!content) {
Content *tmp = [[Content alloc] init];
[self setContent:tmp];
[tmp release];
}
NSString *contentId = [attributeDict objectForKey:@"id"];
[[self content] setContentId:[contentId intValue]];
return;
}
if ([elementName isEqualToString:@"category"]) {
NSString *categoryId = [attributeDict objectForKey:@"id"];
NSString *parentId = [attributeDict objectForKey:@"parent"];
[[self content] setCategoryId:[categoryId intValue]];
[[self content] setParentId:[parentId intValue]];
categoryId = nil;
parentId = nil;
return;
}
if ([elementName isEqualToString:@"vCategory"]) {
NSString *categoryId = [attributeDict objectForKey:@"id"];
NSString *parentId = [attributeDict objectForKey:@"parent"];
[[self video] setCategoryId:[categoryId intValue]];
[[self video] setParentId:[parentId intValue]];
categoryId = nil;
parentId = nil;
return;
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (!currentValue) {
currentValue = [[NSMutableString alloc] initWithCapacity:1000];
}
if (currentValue != @"\n")
[currentValue appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSString *cleanValue = [currentValue stringByReplacingOccurrencesOfString:@"\n" withString:@""] ;
if ([elementName isEqualToString:@"articles"]) {
self.finished = YES;
//[content release];
}
if ([elementName isEqualToString:@"article"]) {
[[self data] addObject:[self content]];
[self setContent:nil];
[self setPhotos:nil];
[self setVideos:nil];
/*
[content release];
content = nil;
[videos release];
videos = nil;
[photos release];
photos = nil;
*/
}
if ([elementName isEqualToString:@"WebTVItem"]) {
[[self data] addObject:[self video]];
[self setVideo:nil];
//[video release];
//video = nil;
}
if ([elementName isEqualToString:@"title"]) {
//NSLog(@"Tit: %@",cleanValue);
[[self content] setTitle:cleanValue];
}
if ([elementName isEqualToString:@"vTitle"]) {
[[self video] setTitle:cleanValue];
}
if ([elementName isEqualToString:@"link"]) {
//NSURL *url = [[NSURL alloc] initWithString:cleanValue] ;
[[self content] setUrl:[NSURL URLWithString:cleanValue]];
[[self content] setLink: cleanValue];
//[url release];
//url = nil;
}
if ([elementName isEqualToString:@"vLink"]) {
[[self video] setLink:cleanValue];
[[self video] setUrl:[NSURL URLWithString:cleanValue]];
}
if ([elementName isEqualToString:@"teaser"]) {
NSString *tmp = [cleanValue stringByReplacingOccurrencesOfString:@"##BREAK##" withString:@"\n"];
[[self content] setTeaser:tmp];
tmp = nil;
}
if ([elementName isEqualToString:@"content"]) {
NSString *tmp = [cleanValue stringByReplacingOccurrencesOfString:@"##BREAK##" withString:@"\n"];
[[self content] setContent:tmp];
tmp = nil;
}
if ([elementName isEqualToString:@"category"]) {
[[self content] setCategory:cleanValue];
}
if ([elementName isEqualToString:@"vCategory"]) {
[[self video] setCategory:cleanValue];
}
if ([elementName isEqualToString:@"date"]) {
[[self content] setDate:cleanValue];
}
if ([elementName isEqualToString:@"vDate"]) {
[[self video] setDate:cleanValue];
}
if ([elementName isEqualToString:@"thumbnail"]) {
[[self content] setThumbnail:[NSURL URLWithString:cleanValue]];
[[self content] setThumbnailURL:cleanValue];
}
if ([elementName isEqualToString:@"vThumbnail"]) {
[[self video] setThumbnailURL:cleanValue];
[[self video] setThumbnail:[NSURL URLWithString:cleanValue]];
}
if ([elementName isEqualToString:@"vDirectLink"]){
[[self video] setDirectLink: cleanValue];
}
if ([elementName isEqualToString:@"preview"]){
[[self video] setPreview: cleanValue];
}
if ([elementName isEqualToString:@"thumbnail_position"]){
[[self content] setThumbnailPosition: cleanValue];
}
if ([elementName isEqualToString:@"url"]) {
if (self.nowPhoto == YES) {
[[self photos] addObject:cleanValue];
}
else if (self.nowVideo == YES) {
[[self videos] addObject:cleanValue];
}
}
if ([elementName isEqualToString:@"photos"]) {
[[self content] setPhotos:[self photos]];
//[photos release];
//photos = nil;
self.nowPhoto = NO;
}
if ([elementName isEqualToString:@"videos"]) {
[[self content] setVideos:[self videos]];
//[videos release];
//videos = nil;
self.nowVideo = NO;
}
//[cleanValue release];
//cleanValue = nil;
[currentValue release];
currentValue = nil;
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"Error" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
-(NSArray*)getData {
return data;
}
-(int)getCount {
return [data count];
}
- (void)dealloc {
[parser release];
//[data release];
//[photos release];
//[videos release];
//[video release];
//[content release];
[currentValue release];
[super dealloc];
}
@end
Где-то в моем коде я создаю экземпляр этого класса:
XMLParser* feed = [[XMLParser alloc] init];
[self setRssParser:feed];
[feed release];
// Parse feed
NSString *url = [NSString stringWithFormat:@"MyXMLURL"];
[[self rssParser] parseXML:[NSURL URLWithString:url]];
Теперь проблема в том, что после первой (с нулевыми утечками) инструменты показывают утечки в слишком многих частях, подобных этой (их слишком много, чтобы перечислить их все, но все вызовы выглядят одинаково, я произвел утечку жирная линия):
в didEndElement:
if ([elementName isEqualToString:@"link"]) {
// THIS LINE IS LEAKING => INSTRUMENTS SAYS IT IS A NSCFString LEAK
[self content] setUrl:[NSURL URLWithString:cleanValue]];
[[self content] setLink: cleanValue];
}
Любая идея, как исправить этот pealse?
Может ли это быть той же проблемой, что и упомянутая (как ошибка с яблоком) Ли Амтронга здесь: NSXMLParser Leaking