2012-04-26 2 views
45

Есть ли разница между использованием подчеркивания и использованием ключевого слова self в Objective-C при вызове @property?Разница между _ и self. в Objective-C

декларация недвижимости:

@property (weak, nonatomic) NSString *myString; 

Вызов @synthesize на имущество:

@synthesize myString = _myString; 

Есть ли разница, если я хочу, чтобы использовать его в своем коде? Когда? В приемнике/сеттере?

self.myString = @"test"; 
_myString = @"test"; 
+0

'self' является символом. '_' является символом в некоторых символах. 'myString' и' _myString' - это два разных символа, которые связаны друг с другом, а не из-за орфографии, а потому, что они названы в том же '@ synthezize'. –

+0

Попробуйте следующий ответ: http://stackoverflow.com/questions/5170631/what-does-synthesize-window-window-do – Peres

+2

Проверьте @ ответ Джонатана на этот предыдущий SO вопрос помогает Http: // StackOverflow .com/questions/5466496/why-rename-synthesized-properties-in-ios-with-leading-underscores – visakh7

ответ

68

self.myString = @"test"; в точности эквивалентен письменной форме [self setMyString:@"test"];. Оба они вызывают метод.

Вы могли бы написать этот метод самостоятельно. Это может выглядеть примерно так:

- (void)setMyString:(NSString*)newString 
{ 
    _myString = newString; 
} 

Потому что вы использовали @synthesize, вы не должны на самом деле потрудились писать этот метод, вы можете просто позволить компилятор, чтобы написать ее для вас.

Так что, глядя на этот метод, похоже, что его вызов будет делать то же самое, что просто присваивать значение переменной экземпляра, правильно? Ну, это не так просто.

Во-первых, вы можете написать свой собственный метод setter. Если вы это сделаете, ваш метод будет вызван, и он сможет делать всевозможные дополнительные вещи, а также устанавливать переменную. В этом случае использование self.myString = вызовет ваш метод, но делать _myString = не будет, и, таким образом, будут использоваться различные функции.

Во-вторых, если вы когда-либо используете Key Value Observing, компилятор делает некоторые очень умные трюки. За кулисами он подклассифицирует ваш класс и переопределяет ваш метод setter (независимо от того, написано ли вы сами или сгенерировано синтезом), чтобы сделать вызовы willChangeValueForKey:, которые необходимы для проверки ключевых значений для работы. Вам не нужно знать, как это работает (хотя довольно интересно, если вы хотите прочитать сном!), Но вам нужно знать, что если вы хотите, чтобы Key Value Observing работала автоматически, вы должны использовать методы setter.

В-третьих, вызов метода сеттера, даже если вы полагаетесь на синтез для записи, дает вам гибкость в будущем. Возможно, вы захотите сделать что-то дополнительно, когда значение будет изменено, и в тот момент, когда вы обнаружите, что хотите это сделать, вы можете вручную написать метод setter - если вы привыкли всегда использовать self.myString =, тогда вы не будете необходимо изменить остальную часть кода, чтобы начать вызов нового метода!

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

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

+0

Обратите внимание, что я не упоминал о последствиях управления памятью. Если вы используете ARC, в этом случае они гораздо менее актуальны, поэтому я пропустил их. –

+0

Хорошее объяснение :) – iTag

+0

Кстати, относительно первого предложения ... Это правда 99% времени, но если у вас есть настраиваемый сеттер (указанный в 'setter =' в объявлении свойства), то две формы не совсем эквивалентны. –

8

Вы правильно - первая версия (self.myString) вызывает синтезированный геттер/сеттер, а второй доступ версии частный переменная-член непосредственно.

Похоже, что вы используете ARC, поэтому в этом случае это не так уж и важно. Однако, если вы не используете ARC, это может иметь значение, поскольку назначение частного элемента напрямую не приведет к автоматическому созданию логики сохранения/освобождения или копирования/выпуска, которая сгенерирована для вас, используя synthesize.

+0

Это два разных символа. Могут быть «аардварк» и другая «зебра» и по-прежнему иметь отношение переменной сеттера/геттера. –

+0

@Hot Licks - Вы правы, что имена неактуальны, но когда я прочитал вопрос, я думаю, он задавался вопросом, какая практическая разница между использованием синтезированного свойства и просто использованием переменной-члена, поддерживающей его. –

+0

@ EricPetroelje - да, это именно то, что я спросил. Благодаря! – Kuba

3

_ (подчеркивание) - это просто соглашение, как описано в this question.

Если вы не префикс доступа к свойствам с помощью self., вы напрямую обращаетесь к базовой переменной, как в c struct. В общем, вы должны делать это только в своих методах init и в специализированных аксессуарах свойств. Это позволяет использовать такие вещи, как вычисляемые свойства, и KVC для работы по назначению.

Смежные вопросы