На первый взгляд может показаться, что ваш пример будет работать, но на самом деле он создает утечку памяти.
По соглашению в Какао и касании Какао любой объект, созданный с использованием [[SomeClass alloc] initX]
или [SomeClass newX]
, создается с сохранением количества единиц. Вы отвечаете за вызов [someClassInstance release]
, когда закончите работу с новым экземпляром, как правило, с помощью метода dealloc
.
Сложность возникает, когда вы назначаете свой новый объект свойству вместо переменной экземпляра. Большинство свойств определены как retain
или copy
, что означает, что они либо увеличивают счетчик сохранения объекта при его установке, либо делают копию объекта, оставляя оригинал нетронутым.
В вашем примере это, вероятно, есть в вашем файле .h
:
@property (retain) EditingViewController *editingViewController;
Итак, в вашем первом примере:
EditingViewController *controller =
[[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];
// (1) new object created with retain count of 1
self.editingViewController = controller;
// (2) equivalent to [self setEditingViewController: controller];
// increments retain count to 2
[controller release];
// (3) decrements retain count to 1
Но для вашего второго примера:
// (2) property setter increments retain count to 2
self.editingViewController =
// (1) new object created with retain count of 1
[[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];
// oops! retain count is now 2
Вызывая метод autorelease
для вашего нового объекта перед передачей его установщику, вы просите пул автоматического выпуска получить право собственности на объект и освободить его некоторое время в будущем, поэтому какое-то время у объекта есть два владельца чтобы соответствовать его счету удержания, и все это - труднопреодолимая Дори.
// (3) property setter increments retain count to 2
self.editingViewController =
// (1) new object created with retain count of 1
[[[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil]
// (2) give ownership to autorelease pool
autorelease];
// okay, retain count is 2 with 2 owners (self and autorelease pool)
Другой вариант - назначить новый объект непосредственно переменной экземпляра, а не установщику свойств. Предполагая, что ваш код назвал базовую переменную экземпляра editingViewController
:
// (2) assignment to an instance variable doesn't change retain count
editingViewController =
// (1) new object created with retain count of 1
[[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];
// yay! retain count is 1
Это тонкое, но критическое различие в коде. В этих примерах self.editingViewController = x
является синтаксическим сахаром для [self setEditingViewController: x]
, но editingViewController
является простой старой переменной экземпляра без какого-либо кода сохранения или копирования, созданного компилятором.
См. Также Почему это приводит к утечке памяти (iPhone)?