Разница между self.name и _name с использованием современного Objective-C

Скажем, это в моем заголовочном файле:

@interface AppDelegate : NSObject <NSApplicationDelegate>

@property (weak) IBOutlet NSSlider *slider;
- (void)doSomething;

@end

…и это *m:

@implementation AppDelegate

- (void) doSomething {[self.slider setFloatValue:0];}

@end

Я новичок в Xcode и Objective C, и я хотел бы использовать и понимать современные «инструменты», представленные Apple в своей документации, а именно ARC, или здесь более конкретно возможность пропустить @synthesize.

Если я правильно понял, @property (weak) IBOutlet NSSlider *slider; делает для меня несколько вещей, в том числе:

  • создание переменной экземпляра с именем _slider;
  • создание геттера с именем slider;
  • создание сеттера с именем setSlider.

Я занимался C++ до сих пор, поэтому я рассматриваю переменные экземпляра как эквивалент того, что я называю (надеюсь, правильно) членами моих классов C++, которые я, кстати, всегда называю _member.

Я понимаю, что весь смысл инкапсуляции в том, что если вы находитесь за пределами данного класса, вам должно использоваться методы доступа для доступа к этим переменным; они являются вашими приватными, поэтому вы не сможете получить к ним доступ через _member, даже если попытаетесь.

Но когда я пишу файл *.m своего класса, _member что-то значит. Возвращаясь к моему примеру, я думаю, что self.slider и _slider эквивалентны. Последнее, естественно, приходит на ум в первую очередь, так как сохраняет несколько символов.

Мой вопрос: являются ли эти два абсолютно эквивалентными?

Я знаю, что это похоже на этот вопрос, например, но вот несколько причин, почему я хотел задать себе вопрос:

  • Я не использую @synthesize, поэтому на самом деле я не тот, кто создает _slider, и мне интересно, имеет ли это значение (я считаю, что это довольно недавнее улучшение ObjC, и большинство ответов по-прежнему относятся к @synthesize);
  • кажется, что в среднем большинство разговоров заканчиваются «так что, просто используйте self.name», но я не понимаю, является ли это просто рекомендацией, соглашением о чем-то более важном (влияющем, скажем, на производительность) ;
  • Точно так же некоторые говорят, что вы должны использовать только _name в таких методах, как dealloc и ему подобных; но я не пишу эти слова благодарности ARC, значит ли это, что я никогда не должен использовать _name? Если да, то почему?

Я надеюсь, что это оправдывает этот пост, я извиняюсь, если я пропустил ранее существовавший ответ. Заранее спасибо за помощь.


person Community    schedule 29.05.2014    source источник
comment
Это утверждение неверно, я понимаю, что весь смысл инкапсуляции в том, что если вы находитесь за пределами данного класса, вы должны использовать средства доступа для доступа к этим переменным; они являются вашими приватными, поэтому вы не сможете получить к ним доступ через _member, даже если попытаетесь. вы можете использовать оператор стрелки для доступа к переменной, например. self->_slider. Кстати, я не предлагаю вам использовать его.   -  person lucianomarisi    schedule 29.05.2014
comment
Аналогичный вопрос: Использовать свойство в расширении класса вместо ivar в посте ARC.   -  person Martin R    schedule 29.05.2014
comment
Это уже подробно описано в Stack Overflow. Найдите свойство [objective-c] в сравнении с ivar или свойство [objective-c] в сравнении с переменной экземпляра.   -  person Rob    schedule 30.05.2014
comment
@lucianomarisi Мне кажется, я что-то здесь упускаю… Если я попробую что-то вроде MyObject->_name вне реализации класса MyClass для этого объекта, Xcode скажет мне: «У MyClass нет члена с именем _name». Разве это не переводит тот факт, что вне реализации вы можете получить доступ к этому члену только через свойство MyObject.name(или [MyObject name])?   -  person    schedule 30.05.2014
comment
Спасибо @MartinR и @Rob; Я думаю, я не использовал правильные ключевые слова, извините.   -  person    schedule 30.05.2014
comment
@aurelienche Эта техника разыменования иваров, как подразумевал lucianomarisi, в настоящее время не одобряется. Вам рекомендуется придерживаться свойства по целому ряду причин (широко обсуждаемых в другом месте). Удачи!   -  person Rob    schedule 30.05.2014
comment
@ aurelienche причина, по которой вы этого не видите, заключается в том, что вам нужно будет объявить переменную экземпляра в заголовке, используя @public. Прочитайте этот вопрос stackoverflow.com/questions/5784875/   -  person lucianomarisi    schedule 30.05.2014
comment
@lucianomarisi Спасибо, это проясняет ситуацию!   -  person    schedule 30.05.2014


Ответы (2)


self.name = компилируется в [self setName:] это сильно отличается от прямой установки переменной.

Одна из основных причин, по которой использование установщика по умолчанию отличается, связана с соблюдением значения ключа, которое часто называют KVO. Использование сеттера будет уведомлять наблюдателей об изменениях, установка _name напрямую не будет.

Это не значит, что вы не можете запускать события самостоятельно с помощью willChangeValueForKey: и didChangeValueForKey:, но реализация по умолчанию справится с этим за вас. Итак, как вы говорите, вне класса, обращающегося к ним, вы должны использовать свойство get/set, но внутри вашего класса переменная напрямую теряет некоторые уведомления. Я уверен, что есть и другие отличия, это первое, что приходит на ум.

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

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOCompliance.html

person utahwithak    schedule 29.05.2014

В основных обстоятельствах, когда вы используете готовые методы доступа, вы, вероятно, могли бы избежать взаимозаменяемого использования _slider или self.slider в своем классе. Они не обязательно эквивалентны в том, как они компилируются, но можно сказать, что функциональность эквивалентна.

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

person DannyMac92    schedule 29.05.2014