Prefixing property names with an underscore in Objective C
我以前避免了我的变量名中的下划线,也许是我大学JAVA时代的保留。所以当我在目标C中定义一个属性时,这是我自然要做的。
1 2 3 4 5 6 7 8 9 10 | // In the header @interface Whatever { NSString *myStringProperty } @property (nonatomic, copy) NSString *myStringProperty; // In the implementation @synthesize myStringProperty; |
但几乎每一个例子都是这样做的
1 2 3 4 5 6 7 8 9 10 | // In the header @interface Whatever { NSString *_myStringProperty } @property (nonatomic, copy) NSString *myStringProperty; // In the implementation @synthesize myStringProperty = _myStringProperty; |
我是否应该克服我对下划线的厌恶,因为这是应该做的一种方式,有没有一个很好的理由让这种样式成为首选样式?
更新:现在有了自动属性合成功能,您可以省去@synthesis,结果与使用
1 | @synthesize myStringProperty = _myStringProperty; |
这清楚地显示了你对苹果的偏好。从那以后,我就学会了不再担心和喜欢下划线。
我总是用下划线。它在局部变量和实例变量之间创建了清晰的区别。它还可以避免在以下情况下出现编译器警告:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | @interface MyClass { NSString *name } @property (nonatomic, copy) NSString *name; - (id) initWithName:(NSString *) name; @end @implementation MyClass @synthesize name; // The following method will result in a compiler warning // (parameter name same as ivar name) - (id) initWithName:(NSString *) name { if (self = [super init]) { self.name = name; } return self; } @end |
编辑:
在不得不忍受投反对票和看完评论后,让我试着表达我的观点:
苹果公司建议ivar与其房产同名。Apple还建议属性以小写字母开头。苹果还建议局部变量以小写字母开头。
现在您遇到了一个问题,因为当您读到一段代码,并且看到一个变量正在被使用时,您不能通过命名约定来判断这个变量是一个ivar变量还是一个局部变量。那太糟糕了。解决方案是对ivar和局部变量有不同的命名约定。这是常识。
实现这种命名约定的方式是不相关的。如果你真的想要,你可以简单地在ivar名字后面加上"Woohaha"。我不在乎(但也许其他人会的)。问题是,那些知道自己在做什么的人已经决定使用"下划线前缀"作为ivar。imho,他们做了正确的决定,即使他们自己的公司推荐了其他的东西。(我所说的开发人员是编写一些主要Apple框架和.NET框架类的人员)
最后,代码质量比遵循一个愚蠢的规则更重要,这个规则甚至没有被鼓吹它的人遵循。
关于您所显示的代码的另一条注释是:不要对字符串属性使用retain。你应该用复印件代替。
有关复制/保留属性的详细信息,请参阅:
nsstring属性:复制还是保留?
苹果公司在2012-02-16修订后的"Cocoa编码指南"中明确说明了前缀为_u的实例变量的命名约定及其原因。
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:
1 2 3 | @implementation MyClass { BOOL _showsTitle; } |
If you synthesize the instance variable using a declared property, specify the name of the instance variable in the @synthesize statement.
1 2 | @implementation MyClass @synthesize showsTitle=_showsTitle; |
https://developer.apple.com/library/mac/documentation/cocoa/conceptive/codingguidelines/articles/namingivarsandtypes.html//apple诳ref/doc/uid/20001284-bajgiije
由斯坦福大学的保罗·海格蒂在iTunes U上的演讲《iPhone应用程序开发CS193P 2011秋季》也解释了这一惯例。
http://itunes.apple.com/itunes-u/ipad-iphone-application-development/id473757255
我知道这个问题很久以前就被问到了,但我自己也有同样的问题,我想分享我的发现。
目前建议的目标C 2.0做法是对IVAR使用与属性相同的名称。您可以在@property声明中选择分配不同的ivar,但事实上,默认情况下,属性的合成访问器将以与属性相同的名称访问ivar,这表明它们希望您遵循的模式。
不管怎样,由于对象仍然需要向自己发送消息来访问属性,所以当您访问属性或直接访问其支持IVAR时,很难混淆,尽管使用2.0点访问属性确实使其更为可能。使用标准消息传递语法使意图更加明确。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | @interface Foo : NSObject { NSNumber *bar; } @property(readwrite, retain) NSNumber * bar @end @implementation Foo @synthesize bar; -(void) baz { NSNumber *numberOne = [NSNumber numberWithInt: 1]; //Both set the value of bar through either the your custom or the synthesized setter method [self setBar:numberOne]; self.bar = numberOne; //Both get the value of bar through your synthesized or your custom accessor method NSNumber *fooBar = [self bar]; fooBar = self.bar; //Both manipulate the bar ivar directly bar = numberOne; fooBar = bar; } @end |
苹果保留了一个以下划线开头的选择器,用于他们自己的"私有"方法,包括属性。不过,我认为他们没有为伊瓦尔保留姓名。
就个人而言,我将避免使用下划线来启动任何类型的变量名。这是一个不透明的惯例。如果其他人使用下划线作为局部变量,而没有下划线作为实例变量呢?如果您在一个方法中不小心省略了下划线,而该方法中定义了一个同名的局部变量,该怎么办?
最好让你的地名和你的名字不同。例如,在setter中,可以使用newname或newvalue。
这纯粹是一个风格问题。
我不知道哪些示例使用了带下划线的ivar样式。苹果官方的例子(如密码练习)没有在ivars前面加上
我将指出,使用核心数据的新导航项目在默认情况下使用尾随下划线,并使变量私有。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @interface MyTestAppDelegate : NSObject <UIApplicationDelegate> { UIWindow *window; UINavigationController *navigationController; @private NSManagedObjectContext *managedObjectContext_; NSManagedObjectModel *managedObjectModel_; NSPersistentStoreCoordinator *persistentStoreCoordinator_; } @interface RootViewController : UITableViewController <NSFetchedResultsControllerDelegate> { @private NSFetchedResultsController *fetchedResultsController_; NSManagedObjectContext *managedObjectContext_; } |
运行时的kvc部分在使用valueforkey时需要一个名称或name ivar:当对象找不到检索该变量的消息时。请参阅http://developer.apple.com/documentation/cococa/conceptive/keyvaluecoding/concepts/searchimplementation.html
如果运行时需要搜索名称,而Apple文档首先提到了名称,那么这可能是一个很好的原因。让我们来看一些sdk类:uinavigationbar.h这个类在所有ivar前面都有下划线,uiview也有…名单还在继续。好吧,也许这就是新的iOS SDK和好的ole ns*类所采用的方式,而不是这样做…错误;它们在头文件中也使用下划线。
苹果在私有API消息和ivar中使用下划线。我不明白为什么他们的示例不推动这种行为,特别是当运行时需要将这种所谓的"命名约定"硬编码到变量搜索路径中时。很高兴看到一致性。
请注意,为了符合kvc,必须遵循严格的命名方案;上面的链接帮助您符合这一点,以便使用运行时的这个方便的特性。