2010-05-19 5 views
2

Je construis une application qui analyse un flux rss. Dans l'application, il y a deux types différents de flux avec des noms différents pour les éléments dans le flux, donc j'ai créé un NSObject NSXMLParser qui prend le nom des éléments de chaque flux avant l'analyse. Voici mon code:Iphone NSXMLParser NSCFString fuite de mémoire

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

} 

Lorsque je crée une instance de la classe que je fais comme ceci:

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

Si Je lance l'application avec l'instrument leaks, les fuites pointent vers l'appel [NSXMLNewsParser parse] dans le NewsFeedParser.m.

Voici une capture d'écran de l'instrument Fuites avec la fuite NSCFStrings:

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

Pour la vie de moi je ne peux pas savoir où ces fuites viennent. Toute aide serait grandement appréciée.

Répondre

0

La fuite s'est produite dans la méthode didStartElement. Je copiais elementName sans le relâcher.

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

    } 

} 
0

Vous pouvez également libérer (si nécessaire) les propriétés attribuées NSMutableString avant d'allouer un autre NSMutableString dans la propriété comme ceci:

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