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

时间:2011-11-16 01:06:36

标签: objective-c

  

可能重复:
  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的自定义代码,这似乎很常见)。

谢谢!

3 个答案:

答案 0 :(得分:9)

我自己多次想知道这件事。对其他人的答案感兴趣,但我发现的一个原因是,当你应该使用getter / setter时,它会强迫你注意你是否直接访问了ivar。

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

VS

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

很容易让self.意外离开...将_意外放入是很困难。

答案 1 :(得分:8)

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

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

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

您可以使用以下内容将y属性合成到x变量:

@synthesize y = x;

现在关于下划线。

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

下划线前缀还表明您指的是实例变量。

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

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

因此,您通常拥有x实例变量的_x属性。

这就是你写的原因:

@synthesize x = _x;

我们举一个例子:

@interface Test: NSObject
{
    int x;
}

@property( readonly ) int x;

@end

这很常见......但现在想象一下这个:

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

我们有一个命名冲突。

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

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

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

- ( id )initWithX: ( int )x
{
    if( ( self = [ super init ] ) )
    {
        _x = x;
    }

    return self;
}

没有冲突,没有命名冲突,改善阅读......只是一个很好的方式......

答案 2 :(得分:1)

当使用self的属性时,很容易忘记“self”:

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

VS

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

如果属性和ivar的名称相同,后面的情况将编译而没有抱怨并且似乎有效...直到它们没有,并且你得到一个奇怪的难以重现的边缘案例错误。

如果ivar的名称略有不同,比如附加一个尾随_,编译器会阻止你并让你明确决定:我想在这里引用属性,还是直接引用ivar?< / p>

(所有这一切,我很懒,经常做@synthesize field;,当我真正需要明确的ivar时,用@synthesize field = field_;替换它,比如当它是自定义设置器写入时间时。)< / p>