NSXMLParser&内存泄漏

时间:2010-04-17 11:06:37

标签: iphone memory-leaks nsxmlparser

我正在使用一个自定义类来解析一个XML文件。使用NSXMLParser。在第一次调用时,一切都很好,但是在第二次,第三次和以后的调用中,仪器在didEndElement,didEndElement和foundCharacters函数内的某些行上显示了数十个内存泄漏。 我用Google搜索并发现有些人遇到这个问题,但我找不到任何可以帮助我的东西。

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

现在的问题是,在第一次(没有泄漏)之后,仪器会显示像这样的太多部件泄漏(它们太多而无法全部枚举,但所有的调用看起来都一样,我做了泄漏行粗体):

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

}

知道怎么解决这个问题吗? 这可能与Lee Amtrong提到的那个(作为一个苹果虫)的问题相同:NSXMLParser Leaking

2 个答案:

答案 0 :(得分:0)

-(BOOL)fetchAndParseRss{
 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

 [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

 //To suppress the leak in NSXMLParser
 [[NSURLCache sharedURLCache] setMemoryCapacity:0];
 [[NSURLCache sharedURLCache] setDiskCapacity:0];

 NSURL *url = [NSURL URLWithString:GALLERY_FEED];
 BOOL success = NO;
 NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
 [parser setDelegate:self];
 [parser setShouldProcessNamespaces:YES];
 [parser setShouldReportNamespacePrefixes:YES];
 [parser setShouldResolveExternalEntities:NO];
 success = [parser parse];
 [parser release];
 [pool drain];
 return success;
}

答案 1 :(得分:0)

this页上所示,您可以执行以下操作以消除泄漏(我发现您不需要setMemoryCapacity或setDiskCapacity调用):

NSData *xml = [NSData
        dataWithContentsOfURL: [NSURL
        URLWithString:@"http://some-xml-url.com/my.xml"]];

NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xml];