简体   繁体   English

在RSS阅读器中需要内存泄漏方面的帮助

[英]Need help with memory leaks in RSS Reader

I'm trying to write a simple RSS reader for the iPhone, and it appeared to be working fine, until I started working with Instruments, and discovered my App is leaking massive amounts of memory. 我正在尝试为iPhone编写一个简单的RSS阅读器,在我开始使用Instruments之前,发现它运行良好,直到发现我的应用程序正在泄漏大量内存。

I'm using the NSXMLParser class to parse an RSS feed. 我正在使用NSXMLParser类来解析RSS feed。 My memory leaks appear to be originating from the overridden delegate methods: 我的内存泄漏似乎是由重写的委托方法引起的:

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string

and

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName

I'm also suspicious of the code that populates the cells from my parsed data, I've included the code from those methods and a few other key ones, any insights would be greatly appreciated. 我也对从解析的数据填充单元格的代码感到怀疑,我已经包括了这些方法和其他一些关键方法中的代码,任何见解将不胜感激。


- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if ([self.currentElement isEqualToString:@"title"]) {
        [self.currentTitle appendString:string];
    } else if ([self.currentElement isEqualToString:@"link"]) {
        [self.currentURL appendString:string];
    } else if ([self.currentElement isEqualToString:@"description"]) {
        [self.currentSummary appendString:string];
    }
}


- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if ([elementName isEqualToString:@"item"]) {
        //asdf
        NSMutableDictionary *item = [[NSMutableDictionary alloc] init];

        [item setObject:currentTitle forKey:@"title"];
        [item setObject:currentURL forKey:@"URL"];
        [item setObject:currentSummary forKey:@"summary"];

        [self.currentTitle release];
        [self.currentURL release];
        [self.currentSummary release];

        [self.stories addObject:item];
        [item release];
    }
}


// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }

    // Configure the cell.
    // Set up the cell
    int index = [indexPath indexAtPosition: [indexPath length] - 1];
    CGRect contentRect = CGRectMake(8.0, 4.0, 260, 20);
    UILabel *textLabel = [[UILabel alloc] initWithFrame:contentRect];
    if (self.currentLevel == 0) {
        textLabel.text = [self.categories objectAtIndex: index];
    } else {
        textLabel.text = [[self.stories objectAtIndex: index] objectForKey:@"title"];
    }
    textLabel.textColor = [UIColor blackColor];
    textLabel.font = [UIFont boldSystemFontOfSize:14];
    [[cell contentView] addSubview: textLabel];
    //[cell setText:[[stories objectAtIndex: storyIndex] objectForKey: @"title"]];
    [textLabel autorelease];
    return cell;
}


- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {   
    if ([elementName isEqualToString:@"item"]) {
        self.currentTitle = [[NSMutableString alloc] init];
        self.currentURL = [[NSMutableString alloc] init];
        self.currentSummary = [[NSMutableString alloc] init];
    }

    if (currentElement != nil) {
        [self.currentElement release];
    }
    self.currentElement = [elementName copy];
}


- (void)dealloc {   
    [currentElement release];
    [currentTitle release];
    [currentURL release];
    [currentSummary release];
    [currentDate release];

    [stories release];

    [rssParser release];
    [storyTable release];

    [super dealloc];
}


// Override to support row selection in the table view.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    // Navigation logic may go here -- for example, create and push another view controller.
    // AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil];
    int index = [indexPath indexAtPosition: [indexPath length] - 1];
    if (currentLevel == 1) {
        StoryViewController *storyViewController = [[StoryViewController alloc] initWithURL:[[stories objectAtIndex: index] objectForKey:@"URL"] nibName:@"StoryViewController" bundle:nil];
        [self.navigationController pushViewController:storyViewController animated:YES];
        [storyViewController release];
    } else {
        RootViewController *rvController = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:nil];
        rvController.currentLevel = currentLevel + 1;
        rvController.rssIndex = index;
        [self.navigationController pushViewController:rvController animated:YES];
        [rvController release];
    }
}

I figured out my problem, all of my memory leaks stemmed from this statement: 我发现了我的问题,我所有的内存泄漏都源于以下语句:

self.stories = [[NSMutableArray alloc] init];

This causes the retain count of stories to be incremented by 2, since the setter calls retain on the newly allocated array. 这会导致故事的保留计数增加2,因为setter调用会保留在新分配的数组上。

I replaced the above statement with this one and it solved my problem: 我用此语句替换了上面的语句,它解决了我的问题:

NSMutableArray *array = [[NSMutableArray alloc] init];
self.stories = array;
[array release];

Another way of fixing your code is this replacing 修复代码的另一种方法是这种替换

self.stories = [NSMutableArray alloc] init];

with

self.stories = [NSMutableArray arrayWithCapacity:10];

The arrayWithCapacity method is autoreleased so you don't need to manually call release. arrayWithCapacity方法是自动释放的,因此您不需要手动调用释放。 (This is true for other classes ie setWithCapacity, stringWithFormat etc) (对于其他类(例如setWithCapacity,stringWithFormat等),这是正确的。

Thanks, Sam 谢谢山姆


PS Not helping your question but these lines look a little unusual : PS不能帮助您解决问题,但是这些行看起来有点不寻常:

[self.currentTitle release];

You should probably be doing this : 您可能应该这样做:

self.currentTitle = nil;

That will release currentTitle the same as your code does but it will also set it to nil which means you can't use it again by mistake! 这将释放与代码相同的currentTitle,但也会将其设置为nil,这意味着您不能再次错误使用它!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM