0

Похоже, я не понимал управления памятью в Objective C ... sigh.Управление памятью в iOS/ManagedObjectContext

У меня есть следующий код (обратите внимание, что в моем случае, 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 в отмеченном месте коды, инструменты находит утечку памяти там. Если я это сделаю, программа выйдет из строя, как только я попытаюсь получить доступ к item.place за пределами метода оскорбления.

Любые идеи?

+0

Было бы полезно вставить объявление свойства 'place', а также определение его метода setter (если оно есть). –

+0

Вы имеете в виду, что сгенерировали ваши геттеры/сеттеры с помощью '@ synhesize'? –

+0

Я использовал @dynamic, поскольку я понял, что это правильно для свойств, привязанных к ManagedObjectContext, как в моем случае – Axel

ответ

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 

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

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

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

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

+0

Я изменил его в соответствии с вашим предложением, но все же инструменты показывают утечки в незнакомых местах. Поскольку весь проект слишком велик, у меня создается впечатление, что я должен сам его исправить. Спасибо за вашу помощь и да: я отправился назначать ноль моим сохраненным свойствам, а не отпускать их. Кажется гораздо более безопасным и должен иметь тот же эффект. – Axel

+0

Я рад, что мое предложение было полезным. Надеюсь, вы исправите все утечки! – petershine

1

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

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

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

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

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

+0

Да, я должен был быть немного более подробным в описании проблемы. Добавлена ​​дополнительная информация. – Axel

+0

Хорошо. Но я думаю, что мои комментарии все еще применяются. Казалось бы, вы «управляете». Начните с удаления всех выпусков. Контекст управляемого объекта обрабатывает код для свойств и будет управлять им правильно. – drekka

+0

«Но поскольку вы используете свойства, вы этого не делаете». Хорошо, не всегда. Если это свойство присваивания (а присваивание является атрибутом свойства по умолчанию), тогда ему все равно нужно управлять памятью, хотя это не очень хорошая идея. Кроме того, это может быть случай, когда у него есть пользовательский сеттер. –