本文转载至 http://blog.csdn.net/ztp800201/article/details/9231617 

前置下划线是一种为了帮助区分实例变量和访问方法的约定。对于编译器来说它只是一种变量重命名而已。

考虑以下代码的区别(不使用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无效的引用

考虑到@synthesize被省略的时候@synthesize var=_var是LLVM 4.0自动生成的你可以把它当做Objective-C的默认命名规则。

更详细的请继续阅读...


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 变量前置下划线解释的更多相关文章

  1. iOS初学,关于变量加下划线问题

    为什么做ios开发,变量前要加下划线才有用? 看到这个哥们的解释后,终于明白了,转帖到此. 链接在此:http://www.cocoachina.com/bbs/read.php?tid=234290 ...

  2. Python变量的下划线

    xx: 公有变量 _x: 单前置下划线,私有化属性或方法,from somemodule import *禁止导入,类对象和子类可以访问 __xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部 ...

  3. 私有化 : _x: 单前置下划线,私有化属性或方法;__xx:双前置下划线;__xx__:双前后下划线;属性property

    私有化 xx: 公有变量 _x: 单前置下划线,私有化属性或方法,from somemodule import *禁止导入,类对象和子类可以访问 __xx:双前置下划线,避免与子类中的属性命名冲突,无 ...

  4. iOS中self.xxx 和 _xxx 下划线的区别

    property (nonatomic,copy) NSString *propertyName; self.propertyName 是对属性的拜访: _propertyName 是对部分变量的拜访 ...

  5. iOS开发-UILabel和UIButton添加下划线

    关于UILabel和UIButton有的时候需要添加下划线,一般有两种方式通过默认的NSMutableAttributedString设置,第二种就是在drawRect中画一条下划线,本文就简单的选择 ...

  6. c语言中变量/函数命名以单下划线(_)和双下划线(__) 开头的意义

    以单下划线(_)表明是标准库的变量 双下划线(__) 开头表明是编译器的变量 建议自己在命名的时候不要用下划线开头,避免与标准库中的命名冲突 命名方法有好多,何必为自己找不自在呢.

  7. Python下划线简介

    Python中下划线的5种含义 分享一篇文章:The Meaning of Underscores in Python. 本文介绍了Python中单下划线和双下划线("dunder" ...

  8. python any,call,init,下划线知识汇总

    python补充 any() [来自菜鸟教程] any() 函数用于判断给定的可迭代参数 iterable 是否全部为 False,则返回 False,如果有一个为 True,则返回 True. 元素 ...

  9. Python下划线与命名规范

    Python下划线与命名规范 先看结论,节省只想知道答案你的宝贵时间: _xxx 不能用于from module import * 以单下划线开头的表示的是protected类型的变量.即保护类型只能 ...

随机推荐

  1. JAVA-JSP之include指令

    相关资料:<21天学通Java Web开发> 结果总结:1.包含的可以是一个HTML文件,也可以是一个文件文件,当然也可以是一个JSP文件.2.只有当被包含的文件执行完成后,JSP文件才会 ...

  2. JavaScript高级 面向对象(2)--调试工具的使用:音乐循环播放

    说明(2017.3.29): 1. 在调试工具console里输入var v = document.createElement("audio"),然后再source的watch里输 ...

  3. C#写的工厂模式

    program.cs file using System; using System.Collections.Generic; using System.Text; namespace Console ...

  4. KafkaStream时间戳问题CreateTime = -1引起的程序中断

    Exception in thread "app-8835188a-e0a0-46da-ac2a-6820ec197628-StreamThread-1" org.apache.k ...

  5. c#生成rsa公钥和私钥

    c#生成rsa公钥和私钥的类库,包括加密解密,可以用在网站和winform项目 源码地址: http://download.csdn.net/detail/jine515073/8383809

  6. Struts2 的Action中取得请求参数值的几种方法

    先看GetRequestParameterAction类代码:  Java代码 public class GetRequestParameterAction extends ActionSupport ...

  7. C# 关于JArray和JObject封装JSON对象

    直入主题,不废话... 1.JObject:基本的json对象 /// <summary> /// Gets the j object. /// </summary> /// ...

  8. selenium测试(Java)--下拉框(二十一)

    例子: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title ...

  9. tensorflow函数学习笔记

    https://www.w3cschool.cn/tensorflow_python/tensorflow_python-4isv2ez3.html tf.trainable_variables返回的 ...

  10. 二叉查找树 _ 二叉排序树 _ 二叉搜索树_C++

    一.数据结构背景+代码变量介绍 二叉查找树,又名二叉排序树,亦名二叉搜索树 它满足以下定义: 1.任意节点的子树又是一颗二叉查找树,且左子树的每个节点均小于该节点,右子树的每个节点均大于该节点. 2. ...