2010-02-12 5 views
5

Недавно кто-то на Stack Overflow сказал мне, что следующий код не попадала, что свойство управляет само удержание:iPhone: Является ли это утечка или нет

self.locationManager = [[CLLocationManager alloc] init]; 

в dealloc:

self.locationManager = nil; 

где в файле .h:

@property (nonatomic, retain) CLLocationManager *locationManager; 

Я думал, что это была очевидная утечка, и полагал, что это должно устранить утечку:

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

Однако он утверждал, что это не сработает, потому что, по его словам, «вы не обладаете авторефератными свойствами класса. Автоматически генерируемый аксессор собственности определяется сохранить отрегулирует задержку автоматически»

И он сделал мне интересно, если он не прав, или я не понял, управление памятью на всех

EDIT 1: Является ли код

self.myName=[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"]; 

чем отличается

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

управления памятью мудр?

Парень говорит, что первый правильный и отказывается от второго. Почему второй будет ТАКОЙ НЕПРАВИЛЬНОЙ? Насколько я могу видеть, как присваивать автореализованные экземпляры некоторым свойствам, но почему-то все еще остается упрямым аргументом, что второй неверен. Я не вижу этого, любая помощь была бы столь желанной.

+1

На вашем EDIT 1, счет сохранения мудрых, они одинаковы. Эти объекты сохраняются только один раз. В ВСЕХ удобных функциях есть неявный авто-релиз. Если вы не видите слово alloc в инструкции init, переменная автореализована. Если вы используете alloc, вы должны использовать autorelease –

ответ

7

Подсчет сохранений и выпусков помогает в этом случае. Это определенно утечка. Ваш объект locationManager будет сохранен 2 раза: один раз по звонкам alloc/init и один раз по собственности. Установка свойства на nil будет только разблокировать locationManager.

Для примеров, приведенных в Редактировании 1, они действительно одинаковы. Похоже, что у другого разработчика есть отвращение к немедленному автореализациям или не совсем понятно, что делает autorelease.

0

Добавьте эту строку под ... Это, очевидно, дает вашему счету сохранения для locationManager. Это скажет вам, нужно ли его выпустить вручную или нет.

NSLog(@"retainCount:%d", [locationManager retainCount]); 

редактировать:

[locationManager release]; 
+0

Нет, нет, я прошу концептуально. Кроме того, NSlogging saveCounts не является хорошей мерой утечек. –

+0

О, хорошо. Ну, наилучшей практикой вы должны сделать это в dealloc, потому что ваш объект не будет выпущен, когда пул авторесурсов будет удален. Отредактировано выше. – Zinc

+0

Из ссылки на класс NSObject: «Важно: этот метод [preserveCount] обычно не имеет значения при отладке проблем с управлением памятью [...], очень маловероятно, что вы можете получить полезную информацию из этого метода.« – jnic

1

@jnic: вы удивительно неправильно. Насколько я понимаю, предыдущее значение свойства отправляется сообщение о выпуске, а не объект, который вы хотите назначить этому свойству. Итак, да, предлагаемый код действительно протекает, и вам нужно отправить сообщение автореферата так же, как вы думали, ahmet emrah

4

Семантика сохраняют вариант свойства:

  • старое значение (если таковое имеется) получает сообщение о разъединении
  • новое значение получает сохранить сообщение

Таким образом, ваш экземпляр CLLocationManager будет иметь счет сохранения 2 после сеттера. Один из выделяет и один из удерживающего устройства. Вы должны отправить релиз сообщение сразу после сеттер:

CLLocationMamnager *aLocationManager = [[CLLocationManager alloc] init]; 
self.locationManager = aLocationManager; 
[aLocationManager release]; 

В качестве альтернативы, добавьте его в autorelease бассейне так, что она будет по крайней мере, в конце концов free'd. Как вы написали сами:

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

Даже лучше, не используйте сохранить вариант свойства. Оставьте его как присвойте (по умолчанию), и вы настроены на работу, так как вы все равно используете сохраненный объект.

+0

Большое спасибо за ответ –

-2

Хорошо, вот сделка.

Когда вы определяете свойство, как так ...

@property (nonAtomic, retain) NSString myName; 

... из-за невозвратов собственности повелевать его на самом деле, как определение его как:

@property (nonAtomic, readwrite, retain, getter=getMyName,setter=setMyName) NSString myName; 

При использовании @synthesize myName; за кулисами, компилятор генерирует метод геттера, который выглядит примерно так:

-(void) setMyName:(NSString *) aString{ 
    if (!(myString==aString) { //test if a string is the same **object** as the current myString 
     if (aString != nil) { // if nil we don't want to send a retain 
      [aString retain]; // increment the retain count by one 
     }   
     [myString release]; //decrement the retain count of the currently assigned string by one. 
     myString=nil; //set the pointer to nil to ensure we don't point to the old string object 
     myString=aString; //assign the newly retained object to the myString symbol  
    } 
} 

Как вы можете видеть, любая строка из любого источника любого ранее сохраненного счета, автореализованная или нет, будет автоматически сохранена методом при назначении и при назначении нового значения будет автоматически выпущена методом. Несколько присваиваний не будут складывать счетчик сохранения. Пока вы используете сгенерированный сеттер, назначенный объект (в данном случае aString) всегда будет иметь счет сохранения, который сохранит его в классе.

Вот почему вы можете сделать это ...

self.myName=[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"];

без того, чтобы сделать это:

self.myName=[[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"] retain]; 

... и не придется беспокоиться, если значение строки внезапно исчезают, когда autoreleasepool водостоки.

Однако, если вы когда-нибудь позвонить ...

[self.myName release]; 

... где-нибудь за пределами dealloc, то объект в собственность моей быть nilled, если вы не отслеживать его неотступно. Точно так же, если вы позвоните ..

[self.myName retain]; 

... в любом месте, то объект в собственность будет течь (возможно, даже после того, как объект само было высвобождены.)

Вот почему я говорю, никогда не сохранять или autorelease какой-либо объект, назначенный или скопированы в собственность. Это не только бессмысленно, но и контрпродуктивно. Из этого следует, что вы хотите только вызывать освобождение по свойству, когда вы закончите с самообъектом, потому что эффективное отслеживание счета удержания с помощью setter означает, что вы можете потерять свойство, даже если вам все еще нужно.

Autorelease никогда не требуется для свойства, поскольку свойство всегда сохраняется самообъектом, и любой другой объект должен обрабатывать внутреннее хранение, если он использует свойство собственного объекта.

Как только вы понимаете, что происходит внутри сгенерированных аксессуаров, правила очевидны. Никогда не сохраняйте объект свойства явно. Никогда не отпускайте объект объекта в dealloc. Никогда не проверяйте объект объекта.

Очевидным следствием этих правил всегда является использование ссылок self.propertyName внутри объекта self, чтобы гарантировать автоматическое управление сохранением свойства.

+0

Dude, self.myName = [NSSting stringWithFormat: @"% @ is correct. ", @" TechZen "]; ТОЧНО так же, как self.locationManager = [[[[CLLocationManager alloc] init] autorelease]; управление памятью. Не могу поверить, как вы его не видите. –

2

следующее утверждение сохраняется в два раза, и как таковой должен быть выпущен дважды:

self.locationManager = [[CLLocationManager alloc] init]; 

Это, вероятно, лучше всего записать следующим образом:

self.locationManager = [[[CLLocationManager alloc] init]autorelease]; 

Теперь эта переменная была сохранена только один раз , и вы можете отпустить его в функции dealloc вашего класса.

Кроме того, если вы запустите следующую строку кода, релиз называется:

locationManager = nil; 

С locationManager синтезируется, когда вы установите его в ноль, он освобождается первым.

Кроме того, если вы сделали следующее, locationManager сначала будет выпущен, а затем сбросить за кадром:

self.locationManager = foo; 

Наконец, следующий будет врезаться с EXC_BAD_ACCESS, потому что вы дважды отпуская locationManager при установке это Foo:

self.locationManager = [[[CLLocationManager alloc] init]autorelease]; 
[locationManager release]; 
self.locationManager = foo; 
1

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