一千萬個為什麽

搜索

NSXMLParser和內存泄漏


I am parsing an xml file using a custom class that instanciates & uses NSXMLParser. On the first call everything is fine but on the second, third and later calls Instruments show tens of memory leaks on certain lines inside didEndElement, didEndElement and foundCharacters functions. I googled it and found some people having this issue, but I didn't find anything that could really help me.

我的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 

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

}

Any idea how to fix this pealse ? Could this be the same problem as the one mentioned (as an apple bug) by Lee Amtrong here :NSXMLParser Leaking

最佳答案

可在中找到頁面,您可以執行以下操作以消除泄漏(我發現您不需要setMemoryCapacity或setDiskCapacity調用):

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

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

轉載註明原文: NSXMLParser和內存泄漏

猜你喜歡