(C)做@synthesize myvar = _myvar(如果有的话)有什么好处?

(Objective C) what is the advantage of doing @synthesize myvar = _myvar (if any)?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
How does an underscore in front of a variable in a cocoa objective-c class work?

我不完全清楚(除了代码的可读性),为什么在创建属性时要创建一个带下划线前缀的内部变量。

既然一切都是内部处理的,为什么还要这样做呢,因为我们没有向getter和setter添加任何代码?

即使我要向getter或setter添加一些代码,我也不明白为什么我不能只检查myvar,而不必检查myvar,然后将其分配给myvar。

有人能给我一些解释吗,除了"因为每个人都这么做吗?"我想了解这个实践背后的全部原因(这似乎很常见,即使没有getter和setter的自定义代码)。

谢谢!


我自己也想过很多次。对其他人的答案感兴趣,但我发现的一个原因是,当您应该使用getter/setter时,它强制您注意是否直接访问ivar。

self.myvar = @"blah";_myvar = @"blah";

VS

self.myvar = @"blah";myvar = @"blah";

不小心把self.号导弹扔出去了…不小心把_放进去要困难得多。


Objective-C属性通常有一个支持实例变量(我想您知道属性和实例变量之间的区别)。

属性的名称可能与实例变量的名称不同。

例如,您可能有一个名为x的实例变量,其属性名为y

您可以使用以下方法将y属性合成为x变量:

1
@synthesize y = x;

关于下划线。

在实例变量具有与实例变量同名的方法参数时,通常使用下划线前缀来防止命名冲突或编译器警告(阴影变量)。

下划线前缀还清楚地表明您所引用的是实例变量。

通过对实例变量使用下划线前缀,您可以在方法的参数、堆栈变量等中使用不带下划线的名称。

但在使用属性时,通常不希望用户编写下划线。

因此,对于一个_x实例变量,通常有一个x属性。

这就是你写作的原因:

1
@synthesize x = _x;

让我们举个例子:

1
2
3
4
5
6
7
8
@interface Test: NSObject
{
    int x;
}

@property( readonly ) int x;

@end

这很常见…但是现在想象一下,在实现中:

1
2
- ( id )initWithX: ( int )x
{}

我们有一个命名冲突。

在我们的方法中,x将引用该方法的参数。而且没有访问x实例变量的好方法。

根据编译器的警告标志,这也可能生成一个警告(-Wshadow)。

如果对实例变量使用下划线前缀,那么一切都很简单:

1
2
3
4
5
6
7
8
9
- ( id )initWithX: ( int )x
{
    if( ( self = [ super init ] ) )
    {
        _x = x;
    }

    return self;
}

没有冲突,没有命名冲突,改进了读取…只是个好办法…


当使用自我的属性时,很容易忘记"自我"。

1
2
3
[self.field doSomething]; // what you probably want
[self setField:someObject]; // also kosher
self.field = someObject; // ditto, although not my style

VS

1
2
[field doSomething] // might work.. but will bite you eventually
field = someObject; // almost certainly wrong anywhere outside a custom setter

如果财产和个人所得税的名称相同,后一种情况将毫无怨言地汇编起来,并似乎有效…直到他们没有,你会得到一个奇怪的难以复制的边缘案例错误。

如果ivar有一个稍有不同的名称,比如附加了一个尾随的_,编译器将停止您并让您明确地决定:我要在这里引用属性,还是直接引用ivar?

(尽管如此,我很懒惰,经常做@synthesize field;,后来当我真正需要独特的ivar时,用@synthesize field = field_;代替它,比如说当它是自定义编写时间时。)