Управление памятью в iOS / ManagedObjectContext

Похоже, я не понял управления памятью в Objective C... вздох.

У меня есть следующий код (обратите внимание, что в моем случае, placemark.thoroughfare а также placemark.subThoroughfare оба заполнены действительными данными, таким образом оба ifусловия будут TRUE

item привязан к ManagedObjectContext, Управляемые переменные в item такие как place есть сеттеры / геттеры, созданные с @dynamic, Таким образом, декларация

@property (nonatomic, retain) NSString *place;
@dynamic place;

Позже в коде, в ReverseGeocoderDelegate, я получаю к нему доступ:

- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark {

if (placemark.thoroughfare) {
    [item.place release];
    item.place = [NSString stringWithFormat:@"%@ ", placemark.thoroughfare];        
} else {
    [item.place release];
    item.place = @"Unknown Place";
}
if (placemark.thoroughfare && placemark.subThoroughfare) {
// *** problem is here ***
    [item.place release];
    item.place = [NSString stringWithFormat:@"%@ %@", placemark.thoroughfare , placemark.subThoroughfare];
}

Если я не отпущу item.place в отмеченном месте в коде Instruments обнаруживает утечку памяти. Если я это сделаю, программа вылетает, как только я пытаюсь получить доступ item.place вне оскорбительного метода.

Есть идеи?

2 ответа

Решение

Прежде всего, я бы изменил логику так:

NSString *newPlace = nil;

if (placemark.thoroughfare && placemark.subThoroughfare) {
    newPlace = [NSString stringWithFormat:@"%@ %@", placemark.thoroughfare , placemark.subThoroughfare];
}
else {
    if (placemark.thoroughfare) {
        newPlace = [NSString stringWithFormat:@"%@ ", placemark.thoroughfare];
    }
    else {
        newPlace = @"Unknown Place";
    }
}

item.place = newPlace;    // Either nil of valid string can be assigned to

Использование release для простой повторной инициализации указателя многими не рекомендуется. Вам не нужно делать это, если это нужно для сохранения памяти.

Ваша предыдущая логика выпускает дважды. То, что делает релиз изначально, просто уменьшается retainCount, Если это 0, то объект освобожден. Объект не будет освобожден до его retainCount это 0.

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

Лучший способ очистить объект несколько раз - просто назначить nil к этому.

Отправной точкой было бы перечитать свойства, потому что вам не нужно нигде делать "[item.place release]". Таким образом, вы можете удалить их. Динамический код, созданный средой выполнения для включения этого свойства, автоматически обрабатывает освобождение всего, что ему было ранее назначено.

Так же [NSString stringWithFormat:... создает объект автоматического освобождения (не уверен, если вы знали, что:-), что означает, что если вы вручную управляете памятью для переменной (не для свойства), вам придется сохранить / освободить ее. Но потому что вы используете свойства, вы не делаете.

Я не могу понять, почему инструменты обнаруживают утечку памяти. Возможно, какой-то код выше связан с этим. Например, если вы пошли item.place = [NSString alloc] initWith...]; тогда я думаю, что тебе это понадобится.

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

Надеюсь, это поможет.

Другие вопросы по тегам