Кто должен нести ответственность за освобождение параметра сеттера?
Пожалуйста, смотрите код следующим образом:
- (void) setSomeThing:(NSString *) someThingNew
{
if(someThing!=someThingNew)
{
[someThingNew retain];
[someThing release];
someThing = someThingNew;
}
}
... ...
- (void) dealloc
{
[someThing release];
[super dealloc];
}
@end
Параметр сеттера someThingNew
был retain
в методе установки, что означает, что его счет сохранения равен 1.
Здесь вопрос: это someThingNew
должен release
?
Или потому что someThing
а также someThingNew
указать на тот же объект, а в dealloc
метод someThing
был release
так someThingNew
указать на nil
?
3 ответа
это someThingNew должен выпустить?
Нет, потому что сейчас someThing
а также someThingNew
указать на тот же адрес. Выпуская someThing
в dealloc (и обнуляя это, чтобы быть безопасным, но это для другого вопроса), вы балансируете удержание в сеттере. Все отлично работает! *
* sidenote: экземпляры NSString
обычно copy
не retain
г, в сеттерах, так что не имеет значения, если вы случайно передали NSMutableString
к этому.
Всякий раз, когда вызывается ваш метод установки, someThingNew сохраняется, а someThing освобождается. Затем новый адрес someThingNew сохраняется в someThing, в результате чего счетчик остается равным 1.
Это остается для класса, пока сам объект не будет освобожден. Когда вызывается dealloc, освобождается указатель someThingNew, в результате чего счетчик остается равным 0.
Ваш код верен: установщик должен сохранить объект, если вы хотите сделать его "сильной" переменной. Но вы не должны выпускать это: это не область ответственности сеттера. Таким образом, в коде, откуда вы вызываете сеттер, вы будете:
- Выделить объект для назначения;
- Позвонить сеттеру;
- Отпустите его, когда он вам больше не нужен.
Вы делаете это хорошо, за исключением того факта, что строки обычно копируются, потому что, поскольку полиморфизм допустим, указатель может указывать на изменяемый строковый объект, таким образом, он может меняться от момента к другому.
Пример:
NSAutoreleasePool* pool=[[NSAutoreleasePool alloc]init];
NSString* newString= [[NSMutableString alloc]initWithString: @"Hello"]; // Retain count 1.
[newString autorelease]; // Still 1 as retain count, but it will be decreased
// when the pool will be drained.
[object setSomeThing: newString]; // Retain count 2.
[pool drain]; // Retain count 1
В этом примере вы ясно видите, почему вам нужно копировать объект, а не сохранять его: это изменяемая строка, поэтому ее можно изменить в любой момент.
Копирование объекта
Если вы копируете объект, то способ вызова метода (то есть приведенный выше код) не изменится, он просто изменит реализацию метода. Что-то вроде этого:
- (void) setSomeThing:(NSString *) someThingNew
{
if(someThing!=someThingNew)
{
[someThing release]; // Retain count decreased by 1.
someThing = [someThingNew copy]; // Retain count 1.
}
}
... ...
- (void) dealloc
{
[someThing release];
[super dealloc];
}
@end