我们如何命名实例/参数值?
作为Objective-C(但长期使用C / ++)程序员的新手,我正在寻找有关变量命名约定的建议/建议。
我个人的喜好是在变量实例中使用前缀,以确保函数内的清晰度并防止函数参数的影子化。但是,我喜欢排除前缀的属性(除非我们还为属性名称加上前缀,否则效果不佳并且看起来很愚蠢)。同样,我可以使用" self.variable"约定,但前提是要使"一切"成为属性。
因此,鉴于以下代码,我们对实例/函数变量的首选命名方式是什么?如果我们不打扰,该如何处理函数参数上的阴影?
@interface GridItem : NSObject { CGRect _rect; ... } @end -(void) initFromRect:(CGRect)rect { _rect = rect; ... }
干杯!
解决方案
回答
我不喜欢将下划线用作任何标识符的前缀,因为C和C ++都保留某些下划线前缀供实现使用。
我认为使用" self.variable"是丑陋的。
通常,我为实例变量使用未经修饰的标识符(即没有前缀也没有后缀)。如果类太复杂了,以致我们忘记了实例变量,那么我们就麻烦了。因此,对于示例,我将使用" rect"作为实例变量的名称,并使用" newRect"或者" aRect"作为参数名称。
回答
就我个人而言,我遵循可可命名约定,使用驼峰式外壳来表示功能和变量,并使用大写的驼峰式外壳来表示对象名称(当然不使用前导NS)。
我发现类型前缀使未编写代码的人变得不透明(因为每个人总是使用不同的前缀),并且在现代IDE中,找出某种类型的代码实际上并不那么困难。
回答
大多数可可项目都使用下划线作为非IBOutlet实例变量的前缀,而对IBOutlet实例变量不使用前缀。
我之所以对IBOutlet实例变量不使用下划线,是因为在加载nib文件时,如果我们有用于连接插座的setter方法,则将调用该setter。但是,此机制不使用键值编码,因此,除非设置器的名称与出口完全相同(例如,set_myField:
),否则不会设置名称带有下划线(例如,_myField)前缀的IBOutlet。非标准和总费用。
另外,请注意,使用诸如self.myProp之类的属性与访问实例变量并不相同。使用属性时,我们正在发送一条消息,就像我们使用了[[self myProp]`这样的方括号表示法一样。所有属性的作用是为我们提供简洁的语法,以便在一行中同时指定getter和setter,并允许我们综合其实现;它们实际上并没有使消息分发机制短路。如果我们想直接访问一个实例变量,但给它加上" self"前缀,则需要将" self"当作一个指针,例如" self-> myProp",它实际上是一种C风格的字段访问。
最后,在编写可可代码时,切勿使用匈牙利表示法,并避免使用其他前缀(例如" f"和" m_"),这些前缀将标记该代码为未"得到它"的人编写的代码,并导致该代码成为被其他可可粉开发商怀疑。
通常,请遵循Apple Developer Connection上《 Cocoa编码指南》文档中的建议,其他开发人员将可以选择并理解代码,并且代码将与使用运行时自省的所有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
我们会看到我正在使用实例变量,该变量直接在我的-init
和-dealloc
方法中引用了Employee
,而我在其他方法中使用了该属性。通常,这是带有属性的良好模式:只能在初始化程序,-dealloc和该属性的getter和setter中触摸该属性的基础实例变量。
回答
安德鲁:实际上有很多可可开发人员根本不使用实例变量前缀。在Smalltalk世界中,它也非常普遍(事实上,我想说在Smalltalk中使用实例变量前缀几乎是闻所未闻的)。
实例变量的前缀一直使我震惊,因为它是一种C ++形式,后来被带入Java和C#。由于Objective-C世界在很大程度上与C ++世界(在Java和Cworld是其继任者)平行,因此这可以解释在不同开发人员之间我们可能会看到的"文化"差异。
回答
通过引入属性,我看到不需要在类实例变量前加上" _"。我们可以设置一个简单的规则(在头文件中进行描述),该类外部要访问的任何变量都必须通过该属性或者通过使用该类上的自定义方法来影响值来进行访问。在我看来,这比在其前面加上" _"的名称要干净得多。它还正确封装了这些值,以便我们可以控制如何更改它们。
回答
我们可以在ivars上使用下划线前缀,并且仍对属性使用非下划线名称。对于合成访问器,只需执行以下操作:
@synthesize foo = _foo;
这告诉编译器使用the_foo ivar合成foo属性。
如果我们编写自己的访问器,则只需在实现中使用下划线ivar并保留非下划线方法名称。
回答
我的风格是混合的,并且确实是PowerPlant时代的遗留物:
我使用的最有用的前缀是功能/方法参数的"输入"和"输出"。这可以一目了然地了解参数的用途,并且确实有助于防止方法参数与实例变量之间发生冲突(我们已经看到多少次参数"表"与同名实例变量发生冲突)。例如。:
- (void)doSomethingWith:(id)inSomeObject error:(NSError **)outError;
然后,我将裸名用于实例变量和属性名称:
然后,我将" the"用作局部变量的前缀:theTable,theURL等。这又有助于区分局部变量和实例变量。
然后按照PowerPlant样式,我使用一些其他前缀:k代表常量,E代表枚举,g代表全局变量,s代表静态变量。
我已经使用这种样式大约12年了。
回答
我遵循克里斯·汉森(Chris Hanson)关于下划线ivar前缀的建议,尽管我承认我也为Iboutlets使用下划线。但是,根据@mmalc的建议,我最近开始将我的IBOutlet
声明移到@ property
行。好处是我所有的ivar现在都有一个下划线,并且称为标准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
回答
虽然我喜欢为下划线使用下划线前缀,但是由于所有重复,我讨厌编写@ synthesize
行(它不是很干)。我创建了一个宏来帮助执行此操作并减少代码重复。因此,代替:
@synthesize employee = _employee;
我这样写:
ddsynthesize(employee);
这是一个使用令牌粘贴的简单宏,可在右侧添加下划线:
#define ddsynthesize(_X_) @synthesize _X_ = _##_X_
唯一的缺点是,它将混淆Xcode的重构工具,并且如果通过重构来重命名该属性,它将不会被重命名。
回答
除了此处所说的内容外,请务必阅读有关可可价值遵守关键值的命名的Cocoa文档。从长远来看,严格遵循此模式将对我们有很大帮助。