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。具体来说,在您的实现文件中,您的
1 | @synthesize missionName = _missionName; |
一般来说,这是:
1 | @synthesize propertyName = _ivarName; |
这只是一个关于可读性的约定,它对编译器没有任何特殊的作用。您将看到人们在私有实例变量和方法名上使用它。苹果公司实际上建议不要使用下划线(如果你不小心的话,你可以覆盖你的超类中的内容),但是你不应该为忽视这个建议而感到难过。:)
我看到的唯一有用的目的是如上所述区分局部变量和成员变量,但这不是必要的约定。当与@property配对时,它会增加合成语句的冗长性——
不要使用下划线,只需在不冲突的方法中使用描述性变量名。当它们必须冲突时,方法中的变量名应使用下划线,而不是可由多个方法使用的成员变量。唯一有用的地方是在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]; } } |
其他答案中缺少的是,使用
编译器将强制您使用
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名称代替下划线,也可以合成变量以使用不带下划线的变量或出口。