Ответ 1
Это артефакт предыдущей версии среды выполнения Objective-C.
Первоначально @synthesize
использовался для создания методов доступа, но время выполнения все еще требовало, чтобы переменные экземпляра были явно заданы:
@interface Foo : Bar {
Baz *_qux;
}
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
Люди будут префикс своих переменных экземпляра, чтобы отличать их от своих свойств (хотя Apple не хочет, чтобы вы использовали символы подчеркивания, но это другое дело). Вы синтезируете свойство, чтобы указать на переменную экземпляра. Но дело в том, что _qux
- это переменная экземпляра, а self.qux
(или [self qux]
) - это сообщение qux
, отправленное объекту self
.
Мы используем переменную экземпляра непосредственно в -dealloc
; используя метод доступа, будет выглядеть так (хотя я не рекомендую его по причинам, которые я объясню вкратце):
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
Это приводит к освобождению qux
, а также к обнулению ссылки. Но у этого могут быть неудачные побочные эффекты:
- Вы можете запустить несколько неожиданных уведомлений. Другие объекты могут наблюдать изменения
qux
, которые записываются, когда для его изменения используется метод доступа. - (Не все согласны в этом вопросе:) Нулевая указатель, поскольку он может скрыть логические ошибки в вашей программе. Если вы когда-либо обращались к переменной экземпляра объекта после, объект был освобожден, вы делаете что-то серьезно неправильно. Однако из-за семантики Objective-C
nil
-messaging вы никогда не узнаете, использовав аксессуар для установки наnil
. Если бы вы выпустили переменную экземпляра напрямую и не обнуляли ссылку, доступ к удаленному объекту вызвал бы громкийEXC_BAD_ACCESS
.
В более поздних версиях среды выполнения добавлена возможность синтезировать переменные экземпляра в дополнение к методам доступа. В этих версиях среды выполнения приведенный выше код можно записать без исключения переменных экземпляра:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
Это фактически синтезирует переменную экземпляра на Foo
, называемую _qux
, к которой обращаются сообщения getter и setter -qux
и -setQux:
.
Я рекомендую против этого: это немного грязно, но есть одна веская причина использовать подчеркивание; а именно, для защиты от случайного прямого доступа к ivar. Если вы считаете, что можете доверять себе, помните, используете ли вы исходную переменную экземпляра или метод доступа, просто сделайте это так:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux;
- (void)dealloc {
[qux release];
[super dealloc];
}
@end
Затем, если вы хотите получить доступ к переменной экземпляра напрямую, просто скажите qux
(который переводит на self->qux
в синтаксис C для доступа к элементу из указателя). Если вы хотите использовать методы доступа (которые будут уведомлять наблюдателей и делать другие интересные вещи и сделать вещи более безопасными и удобными в отношении управления памятью), используйте self.qux
([self qux]
) и self.qux = blah;
([self setQux:blah]
).
Грустная вещь здесь заключается в том, что образец кода Apple и код шаблона отстой. Никогда не используйте его как руководство к правильному стилю Objective-C и, конечно же, никогда не используйте его в качестве руководства к правильной архитектуре программного обеспечения.:)