alloc + init с синтезированным свойством - приводит ли это к тому, что счетчик увеличивается на два? - PullRequest
17 голосов
/ 16 июля 2010

Я немного видел следующий фрагмент:

В заголовке:

SomeClass *bla;
@property(nonatomic,retain) SomeClass *bla;

В файле реализации:

@synthesize bla;

, а затем

self.bla = [[SomeClass alloc] init];

Я думаю, что это назначение увеличивает счет 'бла' на два;один раз через вызов alloc / init, затем через retain, который мы попросили выполнить через установщик синтезированных свойств.

В результате я обычно объявляю свои свойства следующим образом:

В заголовке:

SomeClass *_bla; // note the underscore
@property(nonatomic,retain) SomeClass *bla;

В файле реализации:

@synthesize bla = _bla;

, а затем

_bla = [[SomeClass alloc] init];

При условии, что мое первоначальное предположение верно - мне было бы интересно узнать,есть «правильный» способ сделать это, то есть объявление, инициализация и управление памятью свойств?

Ответы [ 4 ]

8 голосов
/ 16 июля 2010

Я думаю, что это назначение увеличивает количество сохраненных значений для 'bla' на два;

True.

Мне было бы интересно услышатьесть ли «правильный» способ сделать это

Ваш последний фрагмент кода - правильный путь, но подчеркивание не рекомендуется.Свойство и ivar могут иметь одно и то же имя.Достаточно просто

@interface Foo : Bar {
  SomeClass* bla;
}
@property (nonatomic, retain) SomeClass* bla;
@end

@implementation Foo
@synthesize bla;
-(id)init {
   ...
   bla = [[SomeClass alloc] init];
   ...
}
-(void)dealloc {
  [bla release];
  ...
  [super dealloc];
}

.


Некоторые люди могут использовать

SomeClass* foo = [[SomeClass alloc] init];
self.bla = foo;
[foo release];

или

self.bla = [[[SomeClass alloc] init] autorelease];

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

8 голосов
/ 16 июля 2010

Да, вы правы - использование синтезированного установщика свойства retain увеличило бы количество ссылок на экземпляр, которым вы уже владеете (поскольку alloc подразумевает владение).

Просто перейдите ко второй форме, которую вы упомянули в инициализаторах:

_bla = [[SomeClass alloc] init];

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

self.bla = [[[SomeClass alloc] init] autorelease];
3 голосов
/ 17 июля 2010

Похоже, что основной проблемой здесь является неправильное понимание семантики владения объектами в Какао. Для каждого init, copy или retain, вызванного на объекте, должен быть сделан вызов release или autorelease. Здесь происходит то, что вызов init не соответствует вызову release или autorelease.

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

self.bla = [[SomeClass alloc] init];

- это не то же самое, что:

bla = [[SomeClass alloc] init];

Первое переводится как:

[self setBla: [[SomeClass] alloc] init]];

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

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

0 голосов
/ 08 мая 2011

Двойного счета нет. Сеттер, созданный synthesize, делает релиз перед сохранением. См. Стэнфордский класс по задаче 3 класса, как указано на веб-сайте Apple. Стоит также отметить, что в случае с iboutlets выделение init не требуется, поскольку оно выполняется посредством загрузки xib-файла

...