Alloc + init с синтезированным свойством - увеличивает ли счет удержания на два?
Я немного оценил следующий фрагмент:
В заголовке:
SomeClass *bla;
@property(nonatomic,retain) SomeClass *bla;
В файле реализации:
@synthesize bla;
а затем
self.bla = [[SomeClass alloc] init];
Я думаю, что это задание ставит счетчик "bla" на два; один раз через вызов alloc/init, затем через сохранение, которое мы попросили, чтобы произойти с помощью установщика синтезированных свойств.
В результате я обычно объявляю свои свойства следующим образом:
В заголовке:
SomeClass *_bla; // note the underscore
@property(nonatomic,retain) SomeClass *bla;
В файле реализации:
@synthesize bla = _bla;
а затем
_bla = [[SomeClass alloc] init];
Если мое первоначальное предположение верно - мне было бы интересно узнать, есть ли "правильный" способ сделать это, т.е. объявление, инициализация и управление памятью свойств?
Ответы
Ответ 1
Да, вы правы - использование синтезированного setter свойства retain
увеличило бы количество ссылок на экземпляр, который у вас уже есть (поскольку alloc
подразумевает право собственности).
Просто перейдите со второй формой, упомянутой в ваших инициализаторах:
_bla = [[SomeClass alloc] init];
... и не забудьте зафиксировать счет сохранения в противном случае, например:
self.bla = [[[SomeClass alloc] init] autorelease];
Ответ 2
Я думаю, что это задание ставит счетчик "bla" на два:
True.
Мне было бы интересно узнать, есть ли "правильный" способ сделать это
Ваша последняя часть кода - правильный путь, но главное подчеркивание не рекомендуется. Имущество и ивар могут иметь одно и то же имя. Просто
@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
, но я сильно препятствует, поскольку это вызывает ненужное множество методов и вы не можете гарантировать поведение setter.
Ответ 3
Похоже, основная проблема заключается в непонимании семантики владения объектами в Cocoa. Для каждого вызываемого объекта 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
установщиком.
Ответ 4
Нет двойного счета. Создатель, созданный путем синтеза, делает релиз перед выполнением сохранения. См. Класс Стэнфорд на объекте c класса 3, как указано на веб-сайте Apple. Также стоит отметить, что в случае iboutlets init init не требуется, поскольку он выполняется посредством загрузки xib файла