成为Objective-C(但是长期的C / ++)程序员的新手我正在寻找有关变量命名约定的建议/建议。
我个人的偏好是为实例中的清晰度使用前缀作为实例变量,并防止功能参数的阴影。然而,我是排除前缀的属性的粉丝(除非你也为你的属性名称添加前缀,这不是很好,看起来很糟糕)。同样地,我可以使用“self.variable”约定,但前提是我将一切都设为属性。
所以给定下面的代码你的首选实例/函数变量的命名风格是什么?如果你不打扰,你如何处理函数参数的阴影?
@interface GridItem : NSObject
{
CGRect _rect;
...
}
@end
-(void) initFromRect:(CGRect)rect
{
_rect = rect;
...
}
干杯!
答案 0 :(得分:15)
大多数Cocoa项目使用underbar作为非IBOutlet
实例变量前缀,并且对IBOutlet
实例变量不使用前缀。
我不为IBOutlet
实例变量使用下划线的原因是,当加载nib文件时,如果你有一个连接插座的setter方法,那么将调用该setter。 然而此机制不使用键值编码,因此IBOutlet的名称前缀为下划线(例如 _myField
) 不将被设置,除非设置器的名称与插座完全相同(例如 set_myField:
),这是非标准和粗略的。
另外,请注意,使用self.myProp
等属性 与访问实例变量相同。您在使用属性时发送消息,就像使用[self myProp]
之类的括号表示法一样。所有属性都为您提供了一个简洁的语法,用于在一行中指定getter和setter,并允许您合成它们的实现;它们实际上并没有使消息调度机制短路。如果要直接访问实例变量,但在其前面添加self
,则需要将self
视为指针,如self->myProp
,这实际上是C风格的字段访问。
最后,在编写Cocoa代码时不要使用匈牙利符号,并回避其他前缀如“f”和“m_” - 这会将代码标记为由没有“得到它”的人编写并且将会导致它被其他Cocoa开发者怀疑。
一般情况下,请遵循Coding Guidelines for Cocoa中Apple Developer Connection文档中的建议,其他开发人员将能够接收并理解您的代码,并且您的代码将适用于所有Cocoa使用运行时内省的功能。
以下是使用我的约定的窗口控制器类的样子:
// EmployeeWindowController.h
#import <AppKit/NSWindowController.h>
@interface EmployeeWindowController : NSWindowController {
@private
// model object this window is presenting
Employee *_employee;
// outlets connected to views in the window
IBOutlet NSTextField *nameField;
IBOutlet NSTextField *titleField;
}
- (id)initWithEmployee:(Employee *)employee;
@property(readwrite, retain) Employee *employee;
@end
// EmployeeWindowController.m
#import "EmployeeWindowController.h"
@implementation EmployeeWindowController
@synthesize employee = _employee;
- (id)initWithEmployee:(Employee *)employee {
if (self = [super initWithWindowNibName:@"Employee"]) {
_employee = [employee retain];
}
return self;
}
- (void)dealloc {
[_employee release];
[super dealloc];
}
- (void)windowDidLoad {
// populates the window's controls, not necessary if using bindings
[nameField setStringValue:self.employee.name];
[titleField setStringValue:self.employee.title];
}
@end
你会看到我在我的Employee
和-init
方法中直接使用引用-dealloc
的实例变量,而我在其他方法中使用该属性。这通常是一个带有属性的好模式:只需触摸初始值设定项中的属性的基础实例变量,-dealloc
以及属性的getter和setter。
答案 1 :(得分:8)
我遵循Chris Hanson关于下划线ivar前缀的建议,但我承认我也使用下划线来表示IBOutlets。但是,我最近开始根据@mmalc's suggestion将IBOutlet
声明移至@property
行。好处是我的所有ivars现在都有一个下划线和标准的KVC设置器(即setNameField:
)。此外,插座名称在Interface Builder中没有下划线。
@interface EmployeeWindowController : NSWindowController {
@private
// model object this window is presenting
Employee *_employee;
// outlets connected to views in the window
NSTextField *_nameField;
NSTextField *_titleField;
}
- (id)initWithEmployee:(Employee *)employee;
@property(readwrite, retain) Employee *employee;
@property(nonatomic, retain) IBOutlet NSTextField *nameField;
@property(nonatomic, retain) IBOutlet NSTextField *titleField;
@end
答案 2 :(得分:3)
您可以在ivars上使用下划线前缀,并仍然使用非下划线名称作为属性。对于合成访问器,只需执行以下操作:
@synthesize foo = _foo;
这告诉编译器使用the_foo ivar合成foo属性。
如果您编写自己的访问者,那么您只需在实现中使用underbar ivar并保留非underbar方法名称。
答案 3 :(得分:2)
就个人而言,我遵循Cocoa命名约定,使用驼峰套管作为函数和变量,并使用驼峰套管作为对象名称(当然没有前导NS)。
我发现类型前缀使得代码对于没有编写代码的人来说更加不透明(因为每个人总是使用不同的前缀),而在现代IDE中,找出某些类型并不是那么困难。
答案 4 :(得分:2)
随着属性的引入,我认为不需要在类实例变量前加上“_”。您可以设置一个简单的规则(在头文件中描述),必须通过属性访问要在类外部访问的任何变量,或者使用类上的自定义方法来影响值。这对我来说似乎比在他们的前面贴着“_”的名字要清晰得多。它还可以正确封装值,以便您可以控制它们的更改方式。
答案 5 :(得分:1)
我不喜欢使用下划线作为任何标识符的前缀,因为C和C ++都保留了某些下划线前缀供实现使用。
我认为使用“self.variable”是丑陋的。
通常,我对实例变量使用未加修饰的标识符(即没有前缀或后缀)。如果你的课程如此复杂以至于你无法记住实例变量,那你就麻烦了。因此,对于您的示例,我将使用“rect”作为实例变量的名称,并使用“newRect”或“aRect”作为参数名称。
答案 6 :(得分:1)
Andrew:实际上有很多Cocoa开发人员根本不使用实例变量前缀。它在Smalltalk世界中也非常普遍(事实上,我认为在Smalltalk中几乎闻所未闻的是在实例变量上使用前缀)。
实例变量的前缀总是让我感到震惊,因为C ++ - ism被带到了Java,然后被带到了C#。由于Objective-C世界在很大程度上与C ++世界平行,因为Java和C#世界是它的继承者,这可以解释您在不同的开发人员之间可能会看到的“文化”差异。
答案 7 :(得分:1)
我的风格是混合动力,真的是PowerPlant时代的延续:
我使用的最有用的前缀是函数/方法参数的“in”和“out”。这有助于您一目了然地了解参数,并确实有助于防止方法参数和实例变量之间的冲突(有多少次您看到参数“table”与同名的实例变量冲突)。 E.g:
- (void)doSomethingWith:(id)inSomeObject error:(NSError **)outError;
然后我使用裸名称作为实例变量和属性名称:
然后我使用“the”作为局部变量的前缀:theTable,theURL等。再次,这有助于区分本地变量和实例变量。
然后按照PowerPlant样式我使用了一些其他前缀:k代表常量,E代表枚举,g代表全局,s代表静态。
我一直在使用这种风格已有12年了。
答案 8 :(得分:1)
虽然我喜欢在ivars中使用下划线前缀,但我不喜欢写@synthesize
行因为所有重复(它不是很DRY)。我创建了一个宏来帮助完成这个并减少代码重复。因此,而不是:
@synthesize employee = _employee;
我写这个:
ddsynthesize(employee);
这是一个简单的宏,使用令牌粘贴在右侧添加下划线:
#define ddsynthesize(_X_) @synthesize _X_ = _##_X_
唯一的缺点是它会混淆Xcode的重构工具,如果你通过重构重命名该属性,它将不会被重命名。
答案 9 :(得分:1)
除了这里所说的内容之外,请务必阅读关于Key Value Observing兼容命名的Cocoa文档。从长远来看,严格遵循这种模式将对您有很大帮助。