iOS @synthesize var = _var 变量前置下划线解释
前置下划线是一种为了帮助区分实例变量和访问方法的约定。对于编译器来说它只是一种变量重命名而已。
考虑以下代码的区别(不使用ARC的情况下):
self.date = [NSDate date]; // 正确,set方法首先释放原来的值
date = [NSDate date]; // 错误,省略set方法将导致内存泄露
_date = [NSDate date]; // 错误,但是这样很容易看出来它不是一个局部变量
使用ARC的情况下变量将不会内存泄露,但是省略 @property 标志却是错误的:
@property (copy) string;
// ...
self.string = someString; // 正确,string将被复制
string = someString; // 错误,string被保留而不是复制
_string = someString; // 错误,但是这样更容易区别
最坏的情况,Core Data等API是基于KVC消息来实现延迟加载的, 如果你不小心忽略了访问方法,数据将被返回为nil
以下就是为什么使用@synthesize var=_var
的原因
self.var
通过访问方法的引用(包括set和get方法)_var
直接引用(不通过set或者get方法)var
无效的引用
考虑到当
是LLVM 4.0自动生成的你可以把它当做Objective-C的默认命名规则。@synthesize
被省略的时候@synthesize var=_var
更详细的请继续阅读...
Modern runtime
在Objective-C 2.0中你可以这样声明变量:
@interface User : NSObject
@property (nonatomic, assign) NSInteger age;
@end
@implementation User {
@synthesize age; //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;
因为有modern runtime,你要做的就这么多。如果你不提供实例变量,编译器会帮你添加一个。下面是将被编译的代码:
@interface User : NSObject {
NSInteger _age;
}
@end
@implementation User
-(void)setAge:(NSInteger)newAge {
_age=newAge;
}
-(void)age {
return _age;
}
@end
如果你同时添加了ivar和@property将会怎么样呢?如果这个变量有相同的变量名和类型,编译器将直接使用它而不是产生一个新的变量。引用自 The Objective-C Programming Language > Declared Properties >Property Implementation Directives:
由于runtime的关系,访问方法的行为存在不同:
对于modern runtime来说,实例变量在需要的时候生成。如果已经存在一个同名的实例变量,这个已经存在的变量就会被使用。
对于legacy runtime来说,实例变量必须已经在当前类的声明中声明过。如果一个同名实例变量作为属性存在并且它的类型和属性的类型兼容,这个同名实例变量将被使用,否则将发生编译错误。
Legacy runtime
如果要支持legacy runtime,必须提供一个同名并且和属性类型兼容的实例变量或者在@synthesize语句里面指定另外一个已经存在的实例变量。
没用下划线的legacy代码:
@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
What is the best way?
苹果公司不提倡方法使用下划线,但是对于变量,苹果公司是提倡使用下划线的。
苹果关于方法的代码规范: Coding Guidelines for Cocoa: Typographic Conventions:
避免使用前置下划线符号区表示私有,尤其是方法。苹果保留了这条约定。第三方使用将引起命名空间冲突,他们可能不小心覆盖一个他们自己的私有方法,这将导致灾难性的后果。
苹果关于变量的代码规范:Declared Properties and Instance Variables
保证实例变量名明确描述了变量的属性。通常情况下,你不应该直接访问变量而是应该通过访问方法(在init和dealloc方法中,你直接访问变量)。为了帮助标明这一点,在实例变量前加上下划线, 例如:
@implementation MyClass { BOOL _showsTitle; }
ISO/IEC 9899 7.1.3 Reserved identifiers (aka C99):
- 所有以下划线开始接一个大写字母或者另一个下划线的标示符将被保留。
- 所有以下划线开始的标示符将被保留用作文件作用域标示符无论是普通还是标记命名空间。
最重要的是,双下划线开头在传统上保留用作预处理/编译器/库。这防止你在代码中使用__block
,苹果将此引入作为一个新的非标准关键字。
Google Objective-C Style guide:
变量名小写字母开头,混合使用大小写来区分单词。类成员变量加后置下划线。例如: myLocalVariable, myInstanceVariable_. 类成员用作KVO/KVC绑定的可以使用前置下划线当且仅当它无法使用Objective-C 2.0 的 @property
Google的后置下划线并没有使你在Xcode开始自动完成之前多输入一个字符,但是如果下划线写在末尾,你将慢慢发现它原来是一个实例变量。
C++和Core Data属性不提倡使用前置下划线(参见What are the rules about using an underscore in a C++ identifier?)(尝试在model中添加一个前置下划线你将看到"Name must begin with a letter").
无论你怎么选择都不太可能发生冲突,当发生冲突的时候编译器会给出警告。当你犹豫不决的时候,使用默认的LLVM规范:@synthesize var=_var;
原文出自:http://stackoverflow.com/questions/6112283/question-about-synthesize
A leading underscore is a naming convention helpful to differentiate between instance variables and accessors. For the compiler it is just a common ivar rename.
Consider the difference (non ARC code):
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
With ARC variables won't be leaked, but it is still wrong to skip the @property attributes:
@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
Even worst, some APIs like Core Data rely on KVC notifications to perform lazy loading. If you accidentally skip the accessors, your data will come back as nil.
This is the reason you often find @synthesize var=_var
, which makes
self.var
an accessor reference (invoking setters and getters),_var
a direct access reference (skipping setters and getters),- and
var
an invalid reference.
Given that @synthesize var=_var
is autogenerated by LLVM 4.0 when@synthesize
is omitted, you can consider this the default naming convention in Objective-C.
Keep reading for details...
Modern runtime
In Objective-C 2.0 you declare variables like this:
@interface User : NSObject
@property (nonatomic, assign) NSInteger age;
@end
@implementation User {
@synthesize age; // this line can be omitted since LLVM 4.0
@end
which is translated by the compiler as follows:
@interface User : NSObject {
NSInteger age;
}
@end
@implementation User
-(void)setAge:(NSInteger)newAge {
age=newAge;
}
-(void)age {
return age;
}
@end
If you prefer to use the underscore convention just add the following:
@synthesize age=_age;
That's all you need because with the modern runtime, if you do not provide an instance variable, the compiler adds one for you. Here is the code that gets compiled:
@interface User : NSObject {
NSInteger _age;
}
@end
@implementation User
-(void)setAge:(NSInteger)newAge {
_age=newAge;
}
-(void)age {
return _age;
}
@end
What happens if you add both the ivar and the @property? If the variable has the same name and type, the compiler uses it instead generating a new variable. Quoting The Objective-C Programming Language > Declared Properties >Property Implementation Directives:
There are differences in the behavior of accessor synthesis that depend on the runtime:
For the modern runtimes, instance variables are synthesized as needed.If an instance variable of the same name already exists, it is used.
For the legacy runtimes, instance variables must already be declared in the @interface block of the current class.If an instance variable of the same name as the property exists, and if its type is compatible with the property’s type, it is used —otherwise, you get a compiler error.
Legacy runtime
But if you need to support the legacy runtime you must either provide an instance variable with the same name and compatible type of the property or specify another existing instance variable in the @synthesize statement.
So the legacy code without underscores would be:
@interface User : NSObject {
NSInteger age;
}
@property (nonatomic, assign) NSInteger age;
@end
@implementation User
@synthesize age;
@end
Or if you prefer the underscore convention:
@interface User : NSObject {
NSInteger _age;
}
@property (nonatomic, assign) NSInteger age;
@end
@implementation User
@synthesize age = _age;
@end
What is the best way?
Apple discourages the use of underscore in methods, but not on variables!.
Apple on methods: Coding Guidelines for Cocoa: Typographic Conventions:
Avoid the use of the underscore character as a prefix meaning private, especially in methods. Apple reserves the use of this convention. Use by third parties could result in name-space collisions; they might unwittingly override an existing private method with one of their own, with disastrous consequences.
Apple on variables: Declared Properties and Instance Variables
Make sure the name of the instance variable concisely describes the attribute stored. Usually, you should not access instance variables directly, instead you should use accessor methods (you do access instance variables directly in init and dealloc methods).To help to signal this, prefix instance variable names with an underscore (_), for example:
@implementation MyClass { BOOL _showsTitle; }
ISO/IEC 9899 7.1.3 Reserved identifiers (aka C99):
- All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
- All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
On top of that, double leading underscore is traditionally reserved for the vendor of the preprocessor / compiler / library. This avoids the case where you use__block
somewhere in your code, and Apple introduces that as a new non-standard keyword.
Google Objective-C Style guide:
Variable Names Variables names start with a lowercase and use mixed case to delimit words. Class member variables havetrailing underscores. For example: myLocalVariable, myInstanceVariable_. Members used for KVO/KVC bindings may begin with a leading underscore iff use of Objective-C 2.0's @property isn't allowed.
Google's trailing underscore doesn't force you to type one more character before Xcode fires the autocomplete, but you'll realize it is an instance variable slower if the underscore is a suffix.
Leading underscore is also discouraged in C++ (seeWhat are the rules about using an underscore in a C++ identifier?) and Core Data properties (try adding a leading underscore in the model and you'll get "Name must begin with a letter").
Whatever you chose, collisions are unlikely to happen, and if they do, you'll get a warning from the compiler. When in doubt, use the default LLVM way:@synthesize var=_var;
iOS @synthesize var = _var 变量前置下划线解释的更多相关文章
- iOS初学,关于变量加下划线问题
为什么做ios开发,变量前要加下划线才有用? 看到这个哥们的解释后,终于明白了,转帖到此. 链接在此:http://www.cocoachina.com/bbs/read.php?tid=234290 ...
- Python变量的下划线
xx: 公有变量 _x: 单前置下划线,私有化属性或方法,from somemodule import *禁止导入,类对象和子类可以访问 __xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部 ...
- 私有化 : _x: 单前置下划线,私有化属性或方法;__xx:双前置下划线;__xx__:双前后下划线;属性property
私有化 xx: 公有变量 _x: 单前置下划线,私有化属性或方法,from somemodule import *禁止导入,类对象和子类可以访问 __xx:双前置下划线,避免与子类中的属性命名冲突,无 ...
- iOS中self.xxx 和 _xxx 下划线的区别
property (nonatomic,copy) NSString *propertyName; self.propertyName 是对属性的拜访: _propertyName 是对部分变量的拜访 ...
- iOS开发-UILabel和UIButton添加下划线
关于UILabel和UIButton有的时候需要添加下划线,一般有两种方式通过默认的NSMutableAttributedString设置,第二种就是在drawRect中画一条下划线,本文就简单的选择 ...
- c语言中变量/函数命名以单下划线(_)和双下划线(__) 开头的意义
以单下划线(_)表明是标准库的变量 双下划线(__) 开头表明是编译器的变量 建议自己在命名的时候不要用下划线开头,避免与标准库中的命名冲突 命名方法有好多,何必为自己找不自在呢.
- Python下划线简介
Python中下划线的5种含义 分享一篇文章:The Meaning of Underscores in Python. 本文介绍了Python中单下划线和双下划线("dunder" ...
- python any,call,init,下划线知识汇总
python补充 any() [来自菜鸟教程] any() 函数用于判断给定的可迭代参数 iterable 是否全部为 False,则返回 False,如果有一个为 True,则返回 True. 元素 ...
- Python下划线与命名规范
Python下划线与命名规范 先看结论,节省只想知道答案你的宝贵时间: _xxx 不能用于from module import * 以单下划线开头的表示的是protected类型的变量.即保护类型只能 ...
随机推荐
- C语言 · 新建Microsoft Word文档
算法提高 新建Microsoft Word文档 时间限制:1.0s 内存限制:256.0MB 问题描述 L正在出题,新建了一个word文档,想不好取什么名字,身旁一人惊问:“你出的题 ...
- [uart]stty命令使用
中文解释链接:http://linux.51yip.com/search/stty 英文解释链接:http://pubs.opengroup.org/onlinepubs/9699919799/uti ...
- javascript中全局变量的定义
首先确实简单,在js脚本的函数外面使用. 但是要注意点: 不能写到jquery的框框代码里面,之前粗心放到$(function(){ })里面去了. <script type="tex ...
- unsupported major.monor version 51.0 (unable to load *.servlet)………………
unsupported major.monor version 51.0 (unable to load *.servlet)------ 这种异常是因为编译war或者java程序的JDK版本和运行部 ...
- CodeIgniter(3.1.4)框架中-使用多个公共控制器
项目目录结构: 在core/MY_Controller.php文件下: <?php /** * Class MY_Controller * 自定义控制器 */ class MY_Controll ...
- CI循环数组问题
当我们在Controll中把数据传递到view中如: $data['cates_data']=$this->Category_Model->byid_data($id); #调用模型层查询 ...
- java中main函数解析
从写java至今,写的最多的可能就是主函数 public static void main(String[] args) {} 但是以前一直都没有问自己,为什么要这么写,因为在c语言中就没有这样子的要 ...
- 第三百二十节,Django框架,生成二维码
第三百二十节,Django框架,生成二维码 用Python来生成二维码,需要qrcode模块,qrcode模块依赖Image 模块,所以首先安装这两个模块 生成二维码保存图片在本地 import qr ...
- 对于表达式比较长的 for 语句和 if 语句
对于表达式比较长的 for 语句和 if 语句,为了紧凑起见可以适当地去 掉一些空格,如 for (i=0; i<10; i++)和 if ((a<=b) && (c< ...
- web开发之微信公众号---微信公众好开发
--------------------------------------time:2015/11/5 ----------------------------------------------- ...