Пара мыслей:
Лучшая практика не писать сеттеры вообще, чтобы воспользоваться автоматически синтезированных методов доступа). Написание собственных - это только возможность испортить управление памятью или ввести ошибку. Перед тем, как вы напишете, у вас должна быть настоятельная потребность в настраиваемом сетевом устройстве.
Возникающее соглашение, например, имена переменных, должно использовать имя свойства, которому предшествует ведущее подчеркивание (например, для свойства, называемого name
, ivar - _name
). Если вы опустите оператор @synthesize
, компилятор, включенный в последние версии Xcode, сделает это автоматически для вас.
Вопрос о том, что должен сделать сеттер, не имеет смысла, если вы не укажете, какие отличия в памяти у вашей собственности. Я собираюсь предположить, что вы определили свою собственность как retain
.
Изменение свойства на NSMutableString
изменяет поведение вашего объекта, и я бы не советовал, если по какой-то причине вам действительно не нужна изменяемая строка.
Ваш первый пример ничего не делает, если кто-то устанавливает свойство name
на nil
. Но если кто-то хочет установить его на nil
, вы должны (а) освободить старое значение name
; и (b) установите ваш ivar на nil
. (Кстати, мой код ниже использует тот факт, что отправка сообщения объекту nil
ничего не делает, поэтому мне не нужно проверять, является ли оно nil
или нет, в этом случае.)
Таким образом, я предполагаю, что вы есть свойство, определяемое следующим образом:
@property (nonatomic, retain) NSString *name;
и синтезировать линию, либо опущена или выглядит как:
@synthesize name = _name;
Тогда, я думаю, установщик будет выглядеть так:
-(void) setName:(NSString *)name
{
// if you want to program defensively, you might want the following assert statement:
//
// NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__);
if (name != _name)
{
[_name release];
_name = name;
[_name retain];
}
}
Кстати, я предполагаю, что ваш метод init
правильно инициализирует _name
и что dealloc
освобождает его.
- (id)init
{
self = [super init];
if (self) {
_name = nil;
}
return self;
}
- (void)dealloc
{
[_name release];
[super dealloc];
}
Как bblum указывает, что это разумно использовать copy
для NSString
свойств:
@property (nonatomic, copy) NSString *name;
Тогда, я думаю, что сеттер будет выглядеть следующим образом:
-(void) setName:(NSString *)name
{
// if you want to program defensively, you might want the following assert statement:
//
// NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__);
if (name != _name)
{
[_name release];
_name = [name copy];
}
}
Но на самом деле, вы просто не должны писать сеттеры, если вам абсолютно не нужно.
И, наконец, ваш код содержит информацию о том, как найти управление памятью в замешательстве. В то время как вы, безусловно, необходимо, чтобы понять это, я хотел бы сделать два последних предложения:
Рассматривают с помощью Automatic Reference Counting (ARC). Хотя это не избавляет от необходимости понимать, как работает управление памятью (см. Advanced Memory Management Programming Guide), упрощается запись кода, который правильно управляет памятью. Если вы пишете код ручной подсчета ссылок (MRC), очень легко сделать простые ошибки управления памятью, которые ARC позаботится о вас.
Особенно, если вы собираетесь использовать MRC, воспользоваться себя статический анализатор Xcode (в «Анализ» в меню «Продукт» или нажмите сдвиг + команду + B). Это может облегчить поиск многих рутинных проблем управления памятью, которые поражают код MRC. Раздел Finding Memory Leaks руководства пользователя также показывает, как найти утечки при отладке вашего кода, но часто статический анализатор может идентифицировать проблемы, просто изучая ваш код.
Почему вы применяете свой собственный метод «сеттера»? Нет необходимости, если у вас нет другой обработки, кроме того, что вы разместили здесь. – rmaddy
@maddy Я бы сказал, что OP работает из устаревшего учебника или книги. – bbum