cocoa objective-c类中变量前面的下划线是如何工作的?

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

我在一些iPhone示例中看到,属性在变量前面使用了下划线。有人知道这是什么意思吗?或者它是如何工作的?

我使用的接口文件如下:

1
2
3
4
5
6
7
8
@interface MissionCell : UITableViewCell {
    Mission *_mission;
    UILabel *_missionName;
}

@property (nonatomic, retain) UILabel *missionName;

- (Mission *)mission;

我不确定上面所说的是什么,但是当我试图设置任务名称时:

1
aMission.missionName = missionName;

我得到错误:

request for member 'missionName' in something not a structure or union


如果您的ivar使用下划线前缀(这只是一个常见的约定,但很有用),那么您需要做一件额外的事情,以便自动生成的访问器(对于属性)知道要使用哪个ivar。具体来说,在您的实现文件中,您的synthesize应该如下所示:

1
@synthesize missionName = _missionName;

一般来说,这是:

1
@synthesize propertyName = _ivarName;


这只是一个关于可读性的约定,它对编译器没有任何特殊的作用。您将看到人们在私有实例变量和方法名上使用它。苹果公司实际上建议不要使用下划线(如果你不小心的话,你可以覆盖你的超类中的内容),但是你不应该为忽视这个建议而感到难过。:)


我看到的唯一有用的目的是如上所述区分局部变量和成员变量,但这不是必要的约定。当与@property配对时,它会增加合成语句的冗长性——@synthesize missionName = _missionName;,并且在任何地方都是丑陋的。

不要使用下划线,只需在不冲突的方法中使用描述性变量名。当它们必须冲突时,方法中的变量名应使用下划线,而不是可由多个方法使用的成员变量。唯一有用的地方是在setter或init方法中。此外,它将使@synthesis语句更加简洁。

1
2
3
4
-(void)setMyString:(NSString*)_myString
{
    myString = _myString;
}

编辑:有了自动合成的最新编译器特性,我现在使用下划线来表示ivar(很少需要使用ivar来匹配自动合成的功能)。


它实际上并不意味着什么,它只是一些人用来区分成员变量和局部变量的惯例。

至于错误,听起来amission的类型不正确。它的声明是什么?


这仅用于合成属性的命名约定。

当您在.m文件中合成变量时,Xcode将自动为您提供变量智能。


这似乎是有关self.variablename vs.u variablename的问题的"主"项。让我陷入困境的是,我有:

1
2
3
4
5
6
7
...
@interface myClass : parentClass {
className *variableName;    // Note lack of _
}

@property (strong, nonatomic) className  *variableName;
...

这导致self.variablename和_variablename在.m中是两个不同的变量。我需要的是:

1
2
3
4
5
6
7
...
@interface myClass : parentClass {
className *_variableName;    // Note presence of _
}

@property (strong, nonatomic) className  *variableName;
...

然后,在类".m"中,self.variablename和_variablename是等效的。

我仍然不清楚为什么许多例子仍然有效,甚至很难做到这一点。

射线


使用下划线不仅可以在不使用self.member语法的情况下解析ivar,而且还可以提高代码的可读性,因为您知道变量是ivar(因为它的下划线前缀)还是成员参数(没有下划线)。

例子:

1
2
3
4
5
6
7
8
9
10
- (void) displayImage: (UIImage *) image {

    if (image != nil) {
        // Display the passed image...
        [_imageView setImage: image];
    } else {
        // fall back on the default image...
        [_imageView setImage: _image];
    }
}


其他答案中缺少的是,使用_variable可防止您心不在焉地键入variable并访问ivar,而不是(假定预期的)属性。

编译器将强制您使用self.variable_variable。使用下划线使键入variable变得不可能,这减少了程序员的错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)fooMethod {

    // ERROR -"Use of undeclared identifier 'foo', did you mean '_foo'?"
    foo = @1;

    // So instead you must specifically choose to use the property or the ivar:

    // Property
    self.foo = @1;

    // Ivar
    _foo = @1;

}

您可以使用self.variable名称代替下划线,也可以合成变量以使用不带下划线的变量或出口。