Нужна помощь с утечками памяти в RSS Reader - PullRequest
1 голос
/ 24 февраля 2010

Я пытаюсь написать простую программу чтения RSS для iPhone, и она, кажется, работала нормально, пока я не начал работать с Инструментами и обнаружил, что в моем приложении просачивается огромное количество памяти.

Я использую класс NSXMLParser для разбора RSS-канала. Утечки памяти происходят из-за переопределенных методов делегата:

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

и

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

Я также с подозрением отношусь к коду, который заполняет ячейки из моих проанализированных данных, я включил код из этих методов и несколько других ключевых, любые выводы будут с благодарностью.


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

Ответы [ 2 ]

0 голосов
/ 19 апреля 2010

Еще один способ исправить ваш код это замена

self.stories = [NSMutableArray alloc] init];

с

self.stories = [NSMutableArray arrayWithCapacity:10];

Метод arrayWithCapacity автоматически выпущен, поэтому вам не нужно вручную вызывать release. (Это верно для других классов, т.е. setWithCapacity, stringWithFormat и т. Д.)

Спасибо, Сэм


PS Не помогает ваш вопрос, но эти строки выглядят немного необычно:

[self.currentTitle release];

Вы, вероятно, должны делать это:

self.currentTitle = nil;

Это выдаст currentTitle так же, как ваш код, но также установит для него значение nil, что означает, что вы не сможете использовать его снова по ошибке!

0 голосов
/ 25 февраля 2010

Я выяснил свою проблему, все утечки памяти произошли из этого утверждения:

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

Это приводит к тому, что число сохраняемых историй увеличивается на 2, поскольку вызовы установщика сохраняются для вновь выделенного массива.

Я заменил приведенное выше утверждение этим, и оно решило мою проблему:

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