Цель c, Управление памятью членов экземпляра - PullRequest
3 голосов
/ 20 декабря 2011

Я в замешательстве от управления памятью членов экземпляра.У меня есть класс с иваром:

DetailedResultsTableViewController *detailedResultsTableViewController;

и

@property (nonatomic, retain) DetailedResultsTableViewController *detailedResultsTableViewController;

в файле .m:

@synthesize detailedResultsTableViewController;

и

[detailedResultsTableViewController release];

Когда я инициализирую эту переменную:

self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];

Я протестировал retaincount сразу после этого init, и он равен 2 !!!если я отпущу его в конце функции, он попадет в невыделенный объект.Что я делаю неправильно?как я должен инициализировать этот тип переменной?Спасибо !!

Ответы [ 6 ]

4 голосов
/ 20 декабря 2011

Использование свойства и синтеза дает вам новый метод. В этом случае у вас будет новый метод set и get для detailedResultsTableViewController. Это генерируется для вас, когда вы компилируете (т.е. нет кода, который вы должны добавить)

Этот установленный метод будет

- (void)setDetailedResultsTableViewController:(DetailedResultsTableViewController *)c 
{
    if (detailedResultsTableViewController != nil) 
    {
        [detailedResultsTableViewController release];
        detailedResultsTableViewController = nil;
    }
    detailedResultsTableViewController = [c retain];
}

Итак, когда вы звоните

self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] init...];

На самом деле вы звоните

[self setDetailedResultsMapViewController:[[DetailedResultsMapViewControler...]]];

И поэтому вы на самом деле делаете два удержания. Тот, где вы вызываете alloc ... init. а затем другой, потому что вы неявно вызываете setDetailedResultsMapViewController, который затем также выполняет сохранение.

Если вы используете свойства, вы бы использовали

DetailedResultsTableViewController *d = [[DetailedResultsMapViewController alloc] init...]
self.detailedResultsMapViewController = d;
[d release];

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

self.detailedResultsMapViewController = nil;

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

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

4 голосов
/ 20 декабря 2011

Во-первых, вы не должны смотреть на резервный счет, он не очень надежен.

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

Делая это так, вы просачиваетесь:

self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];

вы должны сделать:

DetailedResultsMapViewController *vc = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];
self.detailedResultsMapViewController =vc;
[vc release], vc= nil;

Или использовать Autorelease:

self.detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease];
2 голосов
/ 20 декабря 2011

Вы делаете две вещи не так.

Во-первых:

self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];

должно быть:

self.detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease];

поскольку вы используете self.…, вы используете семантику управления памятью свойства, которая в данном случае равна retain, поэтому она сохраняется снова.

Во-вторых:

Вы использовали retainCount. Который бесполезен при отладке управления памятью.

Если вы хотите узнать, почему это неправильно, посмотрите другие ответы относительно retainCount прямо здесь, на Stack Overflow, или прочитайте более полное описание @ 10b * того, почему вы не должны его использовать.

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

1 голос
/ 20 декабря 2011

Ваш @interface правильный, но ваша реализация немного неправильная:

@implmentation MyClass

//It's good practice to explicitly state the a variable name for this property to use 
//The common approach is to use the property name with a leading underscore
//This prevents accidentally accessing the ivar within the class instead of using the     accessor methods. You should only access the ivar directly within the accessor methods (which in these case are being created for you by  @synthesize), in the designate init method and dealloc
@synthesize detailedResultsTableViewController = _detailedResultsTableViewController;

-(void)dealloc
{
//...
    [_detailedResultsTableViewController release];
//...
}

@end

При доступе к свойству:

myClass.detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease];   

Код, который устанавливает метод, не является "собственным"новое значение, поэтому оно должно autorelease.

1 голос
/ 20 декабря 2011

Если у вас есть сохраненное свойство, оно увеличивает счетчик сохранности для любого self.myProperty =

Alloc также увеличивает счет сохранения. Таким образом, в вашем случае счет удержания равен 2.

Там пара подходов.

  1. Вы можете включить autorelease в свой оператор init alloc
  2. Создайте временную переменную, когда вы настраиваете свой экземпляр, затем, когда вы закончите, присвойте ему свое свойство и отпустите временную переменную.
  3. Брось себя. для этого назначения. Загвоздка в том, что если у вас есть пользовательская функция setMyVariable: она не будет вызываться без self.
  4. Используйте ARC, и вам не нужно беспокоиться об этом.
1 голос
/ 20 декабря 2011

Всякий раз, когда вы объявляете свойство как retain и ссылаетесь на него с помощью self.myiVar, оно будет использовать установщик, и установщик сохранит объект.Кроме того, поскольку вы используете alloc для объекта, это также увеличит счет сохранения до 2, доведя счет хранения до 2.

Как примечание, я бы не стал слишком доверять retainCount, иногда он дает неверные результатыОднако на этот раз это правильно.

Вот несколько вариантов, чтобы избежать сохранения счета 2:

//Refer to it with using the setter
detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];

//Autorelease it after alloc
detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...