2010-05-19 128 views
2

我正在構建一個解析RSS源的應用程序。在應用程序中,有兩種不同類型的提要,它們對提要中的元素具有不同的名稱,所以我創建了一個NSXMLParser NSObject,它在分析之前採用每個提要的元素名稱。這裏是我的代碼:Iphone NSXMLParser NSCFString內存泄漏

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

} 

當我創建類的實例,我不喜歡這樣:

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

如果我使用泄漏工具運行應用程序,泄漏指向NewsFeedParser.m中的[NSXMLNewsParser parse]調用。

這裏是泄漏儀器的屏幕截圖與NSCFStrings泄漏:

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

對於我的生活,我不能揣摩出這些泄漏的來源。任何幫助將不勝感激。

回答

0

泄漏發生在didStartElement方法中。我在複製elementName時未釋放它。

 
- (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

您可能還需要分配另一個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]; 
     } 
    } 
}