Управление памятью в iOS / ManagedObjectContext - PullRequest
0 голосов
/ 16 января 2011

Похоже, я не понял управления памятью в 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 ]

2 голосов
/ 16 января 2011

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

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.

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

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

1 голос
/ 16 января 2011

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

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

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

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

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

...