Переопределение имени свойства синтеза Objective-C

Я пытаюсь понять цель директивы synthesize с переопределением имени свойства. Скажем, у меня есть интерфейс, определенный следующим образом:

@interface Dummy ... {
    UILabel *_dummyLabel;
}

@property (retain, nonatomic) UILabel *dummyLabel;

И в файле реализации у меня есть:

@synthesize dummyLabel = _dummyLabel;

Насколько я понимаю, «dummyLabel» — это просто псевдоним переменной экземпляра «_dummyLabel». Есть ли разница между self._dummyLabel и self.dummyLabel?


person Thomas    schedule 27.09.2010    source источник


Ответы (5)


да. self._dummyLabel не определено, а _dummyLabel — нет.

Синтаксис точки расширяется до простых вызовов методов, поэтому он не специфичен для свойств. Если у вас есть метод с именем -(id)someObject, например, в случае object.someObject, это будет так, как если бы вы написали [object someObject];.

self.dummyLabel  //works
self._dummyLabel //does not work
dummyLabel       //does not work
_dummyLabel      //works
[self dummyLabel];  //works
[self _dummyLabel]; //does not work
person Jacob Relkin    schedule 27.09.2010
comment
Спасибо за быстрый ответ. Хм... хорошо, [self.dummyLabel setText:@...] и [_dummyLabel setText:@...] делают одно и то же? Если да, то я не вижу большого преимущества в переименовании _dummyLabel в dummyLabel. - person Thomas; 27.09.2010
comment
Преимущество наличия другого имени для ivar, чем для свойства, заключается в том, что вы можете легко увидеть в коде, когда вы обращаетесь к тому или другому. - person AndersK; 15.11.2010
comment
Таким образом, self.dummyLabel означает что-то вроде this.getDummyLabel(), а просто _dummyLabel означает this.dummyLabel, если я хочу говорить в терминах Java? - person Mustafa; 28.04.2016

Ваше понимание неверно. dummyLabel — это имя свойства и не псевдоним переменной экземпляра — переменная экземпляра только называется _dummyLabel. Таким образом, для экземпляра Dummy с именем myObject выполняется следующее:

  • [myObject dummyLabel] работает
  • myObject.dummyLabel работает
  • [myObject _dummyLabel] не работает
  • myObject._dummyLabel не работает
  • myObject->dummyLabel не работает
  • myObject->_dummyLabel зависит от видимости ивара (@public, @private, @protected)
  • [myObject valueForKey: @"dummyLabel"] работает
  • [myObject valueForKey: @"_dummyLabel"] зависит от реализации +accessInstanceVariablesDirectly (т. е. будет работать в случае по умолчанию, когда +accessInstanceVariablesDirectly возвращает YES).
person Community    schedule 27.09.2010
comment
Итак, когда я хочу получить доступ к переменной экземпляра в методе, я мог бы использовать _dummyLabel = @"blah" - и это изменит значение напрямую, а не через установщик? Таким образом, я мог бы иметь свойство только для чтения без сеттера, но все же изменить его внутренне, перейдя прямо к ivar? И если я хочу использовать геттер/сеттер из метода класса, я бы просто использовал self.dummyLabel? Или я мог бы также использовать dummyLabel напрямую? - person Oliver Mason; 19.08.2011

Преимущество наличия другого имени для ивара, чем для свойства, заключается в том, что вы можете легко увидеть в коде, когда вы обращаетесь к тому или другому — Андре К.

Я не могу найти кнопку «комментировать», поэтому мне приходится публиковать как «ответ».

Просто хотел расширить комментарий Андре - зная, когда вы используете синтезированные свойства по сравнению с ванильной переменной, вы знаете (особенно в случае сеттеров), когда переменная автоматически сохраняется/копируется/освобождается благодаря вашему хорошему сеттеру, а не манипулируют вручную.

Конечно, если вы все делаете правильно, вам, вероятно, не понадобится помощь сеттера для правильного сохранения/освобождения объектов! Но могут быть и другие сценарии, когда обращение к вашим иварам как self.ivar вместо _ivar может быть полезным, например, когда вы используете пользовательские сеттеры/геттеры вместо синтезированных по умолчанию. Возможно, каждый раз, когда вы изменяете свойство, вы также хотите сохранить его в NSUserDefaults. Итак, у вас может быть такой код:

@interface SOUserSettings : NSObject {

BOOL _autoLoginOn;

}

@property (nonatomic, assign) BOOL autoLoginOn;

@end

@implementation SOUserSettings

@synthesize autoLoginOn = _autoLoginOn;

- (void)setAutoLoginOn:(BOOL)newAutoLoginOnValue {

   _autoLoginOn = newAutoLoginOnValue;
   [[NSUserDefaults standardUserDefaults] setBool:_autoLoginOn forKey:@"UserPrefAutoLoginOn"];
}

@end

Note: This is just illustrative code, there could be a thousand things wrong with it!

Итак, теперь в вашем коде, если у вас есть строка с надписью _autoLoginOn = YES, вы знаете, что она не будет сохранена в NSUserDefaults, тогда как если вы используете self.autoLoginOn = YES, вы точно знаете, что произойдет.

Разница между _autoLoginOn и self.autoLoginOn больше, чем просто семантическая.

person Dev Kanchen    schedule 22.04.2011
comment
Отлично, что вы об этом упомянули! Разница действительно есть! - person guitar_freak; 12.03.2013

Я не вижу большого преимущества в переименовании _dummyLabel в dummyLabel.

В некоторых средах выполнения ObjC вам трудно сделать переменные экземпляра невидимыми для пользователей класса. Для них добавление некоторого префикса (или суффикса) к вашим переменным экземпляра может прояснить (или более ясно), что вы не хотите, чтобы кто-то возился с вашими переменными. Тем не менее, вы не хотите, чтобы эта дрянь воздействовала на ваши общественные функции. Это позволяет вам избавиться от него.

Это также может быть полезно, если вам нужно поддерживать старый интерфейс с одним набором имен одновременно с новым набором API с новым набором имен (setLastname или setSurname).

person Stripes    schedule 27.09.2010

Старый пост, но я думаю, что важно упомянуть, что рекомендуется обращаться к переменным через геттеры и сеттеры (то есть с точечной нотацией). Прямой доступ к полю (_ivar) настоятельно рекомендуется только при его инициализации.

Есть хорошая статья Apple: https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html

Последний абзац:

Вы всегда должны обращаться к переменным экземпляра непосредственно из метода инициализации, потому что во время установки свойства остальная часть объекта может быть еще не полностью инициализирована. Даже если вы не предоставляете собственные методы доступа или не знаете о каких-либо побочных эффектах внутри вашего собственного класса, будущий подкласс вполне может переопределить поведение.

person guitar_freak    schedule 12.03.2013