Ответ 1
Подчеркнутое подчеркивание - это соглашение об именах, которое помогает различать переменные экземпляра и аксессоры. Для компилятора это просто обычное переименование ivar.
Рассмотрим разницу (не ARC-код):
self.date = [NSDate date]; // OK, the setter releases the old value first
date = [NSDate date]; // WRONG, skipping the setter causes a memory leak
_date = [NSDate date]; // WRONG but easier to see it not a local variable
С переменными ARC не будет просочиться, но все же неправильно пропустить атрибуты @property:
@property (copy) string;
// ...
self.string = someString; // OK, string is copied
string = someString; // WRONG string is retained but not copied
_string = someString; // WRONG but hopefully easier to see
Даже в худшем случае некоторые API, такие как Core Data, полагаются на уведомления KVC для выполнения ленивой загрузки. Если вы случайно пропустите подписчиков, ваши данные вернутся в нуль.
Вот почему вы часто находите @synthesize var=_var
, что делает
-
self.var
ссылка для доступа (вызывающие сеттеры и геттеры), -
_var
ссылка на прямой доступ (пропускающие сеттеры и геттеры), - и
var
неверная ссылка.
Учитывая, что @synthesize var=_var
автогенерируется LLVM 4.0, когда @synthesize
опущен, вы можете считать это соглашение об именах по умолчанию в Objective-C.
Продолжайте читать подробнее...
Современное время выполнения
В Objective-C 2.0 вы объявляете такие переменные:
@interface User : NSObject
@property (nonatomic, assign) NSInteger age;
@end
@implementation User {
@synthesize age; // this line can be omitted since LLVM 4.0
@end
который переводится компилятором следующим образом:
@interface User : NSObject {
NSInteger age;
}
@end
@implementation User
-(void)setAge:(NSInteger)newAge {
age=newAge;
}
-(void)age {
return age;
}
@end
Если вы предпочитаете использовать соглашение подчёркивания, просто добавьте следующее:
@synthesize age=_age;
Это все, что вам нужно, потому что с современным временем выполнения, если вы не предоставляете переменную экземпляра, компилятор добавляет ее для вас. Вот код, который компилируется:
@interface User : NSObject {
NSInteger _age;
}
@end
@implementation User
-(void)setAge:(NSInteger)newAge {
_age=newAge;
}
-(void)age {
return _age;
}
@end
Что произойдет, если вы добавите и ivar и @property? Если переменная имеет одинаковое имя и тип, компилятор вместо нее использует новую переменную. Цитирование Objective-C Язык программирования > Объявленные свойствa > Директивы по реализации свойств:
Существуют различия в поведении синтеза аксессуаров, которые зависят от времени выполнения:
Для современных сред выполнения переменные экземпляра синтезируются по мере необходимости. Если переменная экземпляра с тем же именем уже существует, б.
Для устаревшей среды выполнения переменные экземпляра уже должны быть объявлены в блоке @interface текущего класса. Если экземпляр переменная с тем же именем, что и свойство, и если ее тип совместим с типом свойств, он используется - иначе, вы получаете ошибка компилятора.
Устаревшее время выполнения
Но если вам нужно поддерживать устаревшую среду выполнения, вы должны либо предоставить переменную экземпляра с тем же именем и совместимым типом свойства, либо укажите другую существующую переменную экземпляра в операторе @synthesize.
Таким образом, устаревший код без подчеркивания будет выглядеть следующим образом:
@interface User : NSObject {
NSInteger age;
}
@property (nonatomic, assign) NSInteger age;
@end
@implementation User
@synthesize age;
@end
Или, если вы предпочитаете соглашение с подчеркиванием:
@interface User : NSObject {
NSInteger _age;
}
@property (nonatomic, assign) NSInteger age;
@end
@implementation User
@synthesize age = _age;
@end
Каков наилучший способ?
Apple отказывается от использования подчеркивания в методах, но не от переменных!.
Apple о методах: Рекомендации по кодированию для Cocoa: Типографские соглашения:
Избегайте использования подчеркивания символ как префикс, означающий private, особенно в методах.. использование этого соглашения. Использовать в третьи стороны могут привести к коллизии именных пространств; они могли бы невольно переопределять существующие частный метод с одним из своих, с катастрофическими последствиями.
Apple по переменным: Объявленные свойства и переменные экземпляра
Убедитесь, что имя переменной экземпляра кратко описывает атрибут сохранен. Обычно вам не нужно обращаться к переменным экземпляра напрямую, вместо этого вы должны использовать методы доступа (вы получаете доступ переменные экземпляра непосредственно в методах init и dealloc). Чтобы помочь сигнализировать это, префикс имена переменных экземпляра с подчеркиванием (_), например:
@implementation MyClass { BOOL _showsTitle; }
ISO/IEC 9899 7.1.3 Зарезервированные идентификаторы (aka C99):
- Все идентификаторы, начинающиеся с символа подчеркивания и в верхнем регистре письмо или другое подчеркивание всегда зарезервированный для любого использования.
- Все идентификаторы, начинающиеся с подчеркивание всегда зарезервировано для использования как идентификаторы с файловой областью в обоих обычное пространство имен тегов.
Кроме того, двойное лидирующее подчеркивание традиционно зарезервировано для поставщика препроцессора/компилятора/библиотеки. Это позволяет избежать случая, когда вы используете __block
где-то в вашем коде, и Apple вводит это как новое нестандартное ключевое слово.
Google Objective-C Руководство по стилю:
Переменные имена Переменные имена начинаются с нижним регистром и использовать смешанный футляр для разделительные слова. Переменные члена класса имеют завершающие подчеркивания. Для Например: myLocalVariable, myInstanceVariable_. Члены, используемые для Связывание KVO/KVC может начинаться с подчеркивание, если использование Objective-C 2.0 @property не является допускается.
Подчеркнутый символ подчеркивания Google не заставляет вас вводить еще один символ перед тем, как Xcode запускает автозаполнение, но вы поймете, что это переменная экземпляра медленнее, если подчеркивание является суффиксом.
Лидерский подчеркивание также не рекомендуется в С++ (см. Какие правила использования подчеркивания в идентификаторе С++?) и свойства Core Data (попробуйте добавить главное подчеркивание в модели, и вы получите "Имя должно начинаться с буквы" ).
Независимо от того, что вы выбрали, столкновения вряд ли произойдут, и если они это сделают, вы получите предупреждение от компилятора. Если вы сомневаетесь, используйте способ LLVM по умолчанию: @synthesize var=_var;
У меня есть редактирование этого сообщения для чтения Мотивация для украшений ивара от Марка Далримпле. Вы можете проверить это.