Утечка памяти с NSMutableString в парсере XML - PullRequest
0 голосов
/ 01 февраля 2012

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

Устаревшая вещь в том, что эта утечка памяти происходит, только когда я делаю определенный вызов (логин) во второй раз. Когда я делаю другие звонки, у меня не возникает утечка памяти.

NSMutableString, которая дает утечки, является 'textInProgress'.

- (NSDictionary *)objectWithData:(NSData *)data
{


    [dictionaryStack release];
    [textInProgress release];

    dictionaryStack = [[NSMutableArray alloc] init];
    textInProgress = [[NSMutableString alloc] init];

    [dictionaryStack addObject:[NSMutableDictionary dictionary]];

    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    parser.delegate = self;
    BOOL success = [parser parse];
    [parser release];

    if (success)
    {

        NSDictionary *resultDict = [dictionaryStack objectAtIndex:0];
        return resultDict;
    }

    return nil;
}


- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    NSMutableDictionary *parentDict = [dictionaryStack lastObject];
    NSMutableDictionary *childDict = [NSMutableDictionary dictionary];

    [childDict setObject:attributeDict forKey: NODE_ATTR_KEY];

    id existingValue = [parentDict objectForKey:elementName];
    if (existingValue)
    {
        NSMutableArray *array = nil;
        if ([existingValue isKindOfClass:[NSMutableArray class]])
        {
            array = (NSMutableArray *) existingValue;
        }
        else
        {
            array = [NSMutableArray array];
            [array addObject:existingValue];

            [parentDict setObject:array forKey:elementName];
        }

        [array addObject:childDict];
    }
    else
    {

        [parentDict setObject:childDict forKey:elementName];
    }

    [dictionaryStack addObject:childDict];
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    NSMutableDictionary *dictInProgress = [dictionaryStack lastObject];

    if ([textInProgress length] > 0)
    {
        [dictInProgress setObject:textInProgress forKey:NODE_VALUE_KEY];

        [textInProgress release];

        textInProgress = [[NSMutableString alloc] init]; <--- Object leaks here

    }

    [dictionaryStack removeLastObject];
}

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

    [textInProgress appendString:string]; <--- Object leaks here

}

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

Вот также два скриншота утечки в инструментах -> Утечки -> Дерево вызовов leak at XML parser foundCharacters

leak at XML parser didEndElement

Надеюсь, кто-нибудь может мне помочь!


EDIT:

Решением этих утечек было объявление NSMutableString и NSMutableDictionary в качестве свойства. (См. Нил его комментарий)

1 Ответ

2 голосов
/ 01 февраля 2012

Я бы посоветовал вам конвертировать textInProgress в свойство, а не в ivar.Вот так:

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    NSMutableDictionary *dictInProgress = [dictionaryStack lastObject];

    if ([self.textInProgress length] > 0) {

        [dictInProgress setObject:self.textInProgress forKey:NODE_VALUE_KEY];

        self.textInProgress = [NSMutableString string];
    }

    [dictionaryStack removeLastObject];
}

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

    [self.textInProgress appendString:string];
}

И просто убедитесь, что вы выпустите его в dealloc

Подсказка: если вы измените имя соответствующего ивара свойства (например, _textInProgress), вы получите ошибку сборки в каждой точке, где вы использовали ivar ранее, поэтому вы не пропустите никаких изменений от textInProgress до self.textInProgress

...