Странная утечка памяти iPhone в парсере xml - PullRequest
3 голосов
/ 20 июня 2009

Обновление : я редактировал код, но проблема сохраняется ...

Привет всем,
это мой первый пост здесь - я нашел это место отличным ресурсом для решения многих моих вопросов. Обычно я изо всех сил стараюсь что-то исправить самостоятельно, но на этот раз я действительно не знаю, что происходит не так, поэтому я надеюсь, что кто-то может мне помочь.
Я создаю приложение для iPhone, которое анализирует пару XML-файлов с помощью TouchXML. У меня есть класс XMLParser, который заботится о загрузке и разборе результатов. Я получаю утечки памяти, когда я анализирую XML-файл более одного раза с одним и тем же экземпляром XMLParser. Вот один из фрагментов анализа (только соответствующая часть):

for(int counter = 0; counter < [item childCount]; counter++) {  
        CXMLNode *child = [item childAtIndex:counter];
        if([[child name] isEqualToString:@"PRODUCT"]) 
        {
            NSMutableDictionary *product = [[NSMutableDictionary alloc] init];
            for(int j = 0; j < [child childCount]; j++) {
                CXMLNode *grandchild = [child childAtIndex:j];
                if([[grandchild stringValue] length] > 1) {
                    NSString *trimmedString = [[grandchild stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
                    [product setObject:trimmedString forKey:[grandchild name]];
                }
            }

            // Add product to current category array
            switch (categoryId) {
                case 0:
                    [self.mobil addObject: product];
                    break;
                case 1:
                    [self.allgemein addObject: product];
                    break;
                case 2:
                    [self.besitzeIch addObject: product];
                    break;
                case 3:
                    [self.willIch addObject: product];
                    break;
                default:
                    break;
            }
            [product release];
        }

    }  

В первый раз, когда я анализирую xml, в инструментах нет утечек, в следующий раз я получаю много утечек (NSCFString / NSCFDictionary). Инструменты указывают мне на эту часть внутри CXMLNode.m , когда я копаюсь в протекшем объекте:

theStringValue = [NSString stringWithUTF8String:(const char *)theXMLString];
if ( _node->type != CXMLTextKind )
   xmlFree(theXMLString);
}

return(theStringValue);  

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

Любая помощь высоко ценится, спасибо!

Ответы [ 3 ]

3 голосов
/ 20 июня 2009

Вероятна проблема в этой строке:

[self.mobil addObject:[product copy]];

Вызывая копию product, вы создаете новый экземпляр NSMutableDictionary с счетчиком сохранения 1. Однако экземпляр mobil будет увеличивать счет сохранения копии при отправке ему сообщения addObject: таким образом, количество сохраненных копий теперь равно 2. Вообще говоря, объект отвечает за обработку собственной памяти объекта, поэтому каждый раз, когда вы отправляете сообщение setFoo: или addObject:, вы можете просто передать объект напрямую, даже если его автоматическое освобождение или вы планируете выпустить его сразу после звонка; ответственность за сохранение объекта, который вы передаете, лежит на получателе, если он должен удерживать его.

Поскольку вы не присвоили копию какой-либо переменной, у вас нет указателя, который можно использовать для уменьшения счетчика хранения копии сейчас, когда она вам больше не интересна, поэтому даже если mobil выпустит продукт скопировать в какой-то момент, копия никогда не достигнет счет сохранения 0. Ваш оператор [product release] в конце цикла for освобождает исходный объект product, а не созданную вами копию.

Вместо этого попробуйте следующее и посмотрите, являются ли инструменты более счастливыми:

[self.mobil addObject:product];
1 голос
/ 20 июня 2009

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

1) У меня был изменяемый массив, настроенный как переменные экземпляра, например:

@interface XMLParser : NSObject {

// ...  
NSMutableArray *mobil;  
// ...  
}   
@property(nonatomic, retain) NSMutableArray *mobil;  
@end  

Каждый раз, когда я хотел восстановить новые данные внутри, я делал:
self.mobil = ноль;
Что не то, что я хотел сделать, так что это лучший подход:
[self.mobil removeAllObjects];

2) Метод dealloc должен быть таким, чтобы исправить утечки (потому что mobil определяется как свойство):
- (недействительно) dealloc {
[мобил релиз];
self.mobil = ноль;
}

Уфф, это было много работы, чтобы выяснить - надеюсь, это сэкономит кому-то еще время :-)

1 голос
/ 20 июня 2009

Проще говоря, каждый раз, когда вы используете copy, вам также нужно где-то использовать release / autorelease.

И в этом случае, еще более простой ответ - не использовать copy, поскольку вы ничего не делаете с исходной версией product после того, как скопировали ее.

...