Главное подчеркивание - это соглашение об именах, которое помогает различать переменные экземпляра и методы доступа.Для компилятора это просто обычное переименование 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's 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> Объявленные свойства> Директивы реализации свойств :
Существуют различия в поведении синтеза средства доступа, которые зависят от времени выполнения:
Для современных сред выполнения переменные экземпляра синтезируются по мере необходимости. Если переменная экземпляра с таким именем уже существует, она используется.
Для устаревших сред выполнения переменные экземпляра уже должны быть объявлены в блоке @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 в методах: Правила кодирования для какао: типографские условные обозначения :
Избегайте использования символа подчеркивания в качестве префикса, означающего приватный, особенно в методах. Apple оставляет за собой право использовать это соглашение.Использование третьими лицами может привести к столкновениям пространства имен;они могут невольно переопределить существующий частный метод своим собственным, что приведет к катастрофическим последствиям.
Apple для переменных: Объявленные свойства и переменные экземпляра
Убедитесь, что имя переменной экземпляра кратко описывает хранимый атрибут.Обычно вы не должны обращаться к переменным экземпляра напрямую, вместо этого вы должны использовать методы доступа (вы обращаетесь к переменным экземпляра непосредственно в методах init и dealloc). Чтобы помочь сигнализировать об этом, префикс имен переменных экземпляра подчеркиванием (_) , например: @implementation MyClass { BOOL _showsTitle; }
ISO / IEC 9899 7.1.3 Зарезервированные идентификаторы (он же C99):
- Все идентификаторы, которые начинаются с подчеркивания и либозаглавная буква или другое подчеркивание всегда зарезервировано для любого использования.
- Все идентификаторы, которые начинаются со знака подчеркивания, всегда зарезервированы для использования в качестве идентификаторов с областью действия файла как в обычном пространстве, так и в пространстве имен тега.
Вдобавок к этому, дваждыначальное подчеркивание традиционно зарезервировано для поставщика препроцессора / компилятора / библиотеки.Это исключает случай, когда вы используете __block
где-то в своем коде, и Apple вводит это как новое нестандартное ключевое слово.
Руководство по стилю Google Objective-C :
Имена переменных Имена переменных начинаются со строчной буквы и используют смешанный регистр для разделения слов.Переменные-члены класса имеют завершающие подчеркивания.Например: myLocalVariable, myInstanceVariable_.Члены, используемые для привязок KVO / KVC, могут начинаться с подчеркивания, если использование @property в Objective-C 2.0 не разрешено.
Завершающее подчеркивание Google не заставляет вас вводить еще односимвол перед Xcode запускает автозаполнение, но вы поймете, что это переменная экземпляра медленнее, если подчеркивание является суффиксом.
В C ++ также не рекомендуется использовать начальное подчеркивание (см. Каковы правила использованияподчеркивание в идентификаторе C ++? ) и свойства Core Data (попробуйте добавить начальное подчеркивание в модель, и вы получите «Имя должно начинаться с буквы»).
Что бы вы ни выбрали, коллизиивряд ли произойдет, и если они это сделают, вы получите предупреждение от компилятора.В случае сомнений используйте способ LLVM по умолчанию: @synthesize var=_var;
У меня есть правка этого поста на чтение Мотивация для украшений ивара Марка Далримпла.Вы можете проверить это.