Цель-C: Исправление управления памятью в методе - PullRequest
5 голосов
/ 27 февраля 2009

Я почти там разбираюсь в простом подсчете ссылок / управлении памятью в Objective-C, однако у меня возникают трудности со следующим кодом. Я выпускаю mutableDict (прокомментировано в коде ниже), и это вызывает вредное поведение в моем коде. Если я позволю утечке памяти, она будет работать, как и ожидалось, но это явно не ответ здесь. ;-) Может быть, кто-нибудь из вас, более опытных, будет достаточно любезен, чтобы указать мне правильное направление, например, как я могу переписать любой из этих методов, чтобы лучше справляться с моей памятью? Главным образом с тем, как я управляю NSMutableDictionary * mutableDict, так как это большой виновник здесь. Я хотел бы понять проблему, а не просто скопировать / вставить код - поэтому некоторые комментарии / отзывы идеальны. Спасибо всем.

- (NSArray *)createArrayWithDictionaries:(NSString *)xmlDocument 
                               withXPath:(NSString *)XPathStr {

    NSError *theError = nil;
    NSMutableArray *mutableArray = [[[NSMutableArray alloc] init] autorelease];
    //NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
    CXMLDocument *theXMLDocument = [[[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError] retain]; 
    NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];
    int i, j, cnt = [nodes count];
    for(i=0; i < cnt; i++) {
        CXMLElement *xmlElement = [nodes objectAtIndex:i];
        if(nil != xmlElement) {
            NSArray *attributes = [NSArray array];
            attributes = [xmlElement attributes];
            int attrCnt = [attributes count];
            NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
            for(j = 0; j < attrCnt; j++) {
                if([[[attributes objectAtIndex:j] name] isKindOfClass:[NSString class]]) 
                    [mutableDict setValue:[[attributes objectAtIndex:j] stringValue] forKey:[[attributes objectAtIndex:j] name]];
                else 
                    continue;
            }
            if(nil != mutableDict) {
                [mutableArray addObject:mutableDict];
            }
            [mutableDict release];  // This is causing bad things to happen.
        }
    }

    return (NSArray *)mutableArray;
}

Ответы [ 3 ]

5 голосов
/ 27 февраля 2009

Вот эквивалентная перезапись вашего кода:

- (NSArray *)attributeDictionaries:(NSString *)xmlDocument withXPath:(NSString *)XPathStr {
    NSError *theError = nil;
    NSMutableArray *dictionaries = [NSMutableArray array];
    CXMLDocument *theXMLDocument = [[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError]; 
    NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];

    for (CXMLElement *xmlElement in nodes) {
        NSArray *attributes = [xmlElement attributes];
        NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
        for (CXMLNode *attribute in attributes) {
            [attributeDictionary setObject:[attribute stringValue] forKey:[attribute name]];
        }

        [dictionaries addObject:attributeDictionary];
    }

    [theXMLDocument release];
    return attributeDictionaries;
}

Обратите внимание, что я делал ссылки только на theXMLDocument. Это потому, что массивы и словари живут за рамками этого метода. Методы класса array и dictionary создают автоматически выпущенные экземпляры объектов NSArray и NSMutableDictionary. Если вызывающая сторона не сохраняет их явно, они будут автоматически освобождены при следующем цикле обработки цикла приложения.

  • Я также удалил код, который никогда не собирался выполняться. Метод CXMLNode name сообщает, что возвращает строку, поэтому проверка всегда будет истинной.
  • Если mutableDict равен nil, у вас большие проблемы. Лучше, чтобы он выдавал исключение, чем беззвучный сбой, поэтому я и покончил с этим тестом.
  • Я также использовал относительно новый синтаксис перечисления for, который отменяет переменные вашего счетчика.
  • Я переименовал некоторые переменные и метод, чтобы быть немного более какао-иш. Какао отличается от большинства языков тем, что обычно считается неправильным использовать глагол типа «создать», если вы не хотите, чтобы вызывающая сторона отвечала за освобождение возвращаемого вами объекта.
  • Вы ничего не сделали с theError. Вы должны либо проверить это и сообщить об ошибке, либо ввести nil, если вы не собираетесь проверять это. Нет смысла заставлять приложение создавать объект ошибки, который вы не собираетесь использовать.

Надеюсь, это поможет вам указать правильное направление.

1 голос
/ 27 февраля 2009

Что ж, выпуск mutableDict действительно не должен вызывать никаких проблем, потому что строка над ним (добавление mutableDict в mutableArray) сохранит его автоматически. Хотя я не уверен, что именно происходит с вашим кодом (вы не указали, что означают «плохие вещи»), я бы предложил несколько общих вещей:

  1. Не делайте autorelease mutableArray прямо сейчас. Пусть это будет регулярный оператор alloc / init и автоматически высвобождается при его возврате («return [mutableArray autorelease];»).

  2. theXMLDocument просачивается, обязательно верните его перед возвратом. Кроме того, вам не нужно сохранять его таким, какой вы есть. alloc / init выполняет эту работу, начиная с сохранения значения счетчика в 1, и повторное его сохранение просто гарантирует, что оно будет утечко навсегда. Избавьтесь от удержания и отпустите его перед возвратом, и он не протечет.

  3. Просто подсказка: убедитесь, что вы сохраняете возвращаемое значение этого метода при использовании его в другом месте - результат был автоматически выпущен, поскольку не обязательно будет рядом, когда он вам нужен, если вы явно не сохраните / не освободите его где-то.

В противном случае этот код должен работать. Если этого не произойдет, я бы попробовал еще одну вещь: возможно, сделайте [mutableArray addObject: [mutableDict copy]], чтобы гарантировать, что mutableDict не вызовет у вас никаких проблем при выпуске.

0 голосов
/ 09 сентября 2010

В Руководство по программированию управления памятью в теме Возвращение объектов из методов (прокрутите немного вниз), есть несколько простых примеров того, как вернуть объекты из метода с помощью правильное управление памятью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...