你如何命名实例/参数值?

4
作为一个刚接触Objective-C的C/C++程序员,我需要关于变量命名的建议和推荐。个人喜好是在实例变量前加上前缀,以便函数内清晰地理解和防止函数参数遮蔽。但是我又喜欢属性,这排除了使用前缀的可能性(除非你也给属性名加上前缀,但这看起来很愚蠢)。同样地,我可以使用"self.variable"的约定,但前提是我必须把所有变量都变成属性。
所以,基于下面的代码,你更喜欢实例/函数变量用哪种命名风格?如果你不在意,那么你是如何处理函数参数遮蔽的?
@interface GridItem : NSObject
{
    CGRect _rect;
    ...  
}
@end

-(void) initFromRect:(CGRect)rect
{
    _rect = rect;
    ...
}

干杯!

10个回答

15
大多数Cocoa项目使用下划线作为非`IBOutlet`实例变量前缀,并对`IBOutlet`实例变量不使用前缀。
我不使用下划线作为`IBOutlet`实例变量的原因是,当加载nib文件时,如果您有一个连接的outlet的setter方法,那么该setter将被调用。然而,这种机制并不使用键值编码,因此以下划线为前缀命名的IBOutlet(例如 `_myField`)将不会被设置,除非setter的名称与outlet完全相同(例如 `set_myField:`),这是不标准和丑陋的。
此外,请注意,使用像`self.myProp`这样的属性与访问实例变量不同。当您使用属性时,您正在发送一条消息,就像使用方括号表示法`[self myProp]`一样。所有属性都做的是为指定getter和setter提供简洁的语法,并允许您综合它们的实现。它们实际上并没有短路消息分发机制。如果要直接访问实例变量但带有`self`前缀,则需要将`self`视为指针,例如`self->myProp`,这确实是一种C样式的字段访问。
最后,编写Cocoa代码时不要使用匈牙利命名法,并避免使用其他前缀,如"f"和"m_" - 这将标记该代码是由一个不理解的人编写的,并会导致其他Cocoa开发人员对其持怀疑态度。一般来说,请遵循苹果开发者连接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中操作属性的底层实例变量。


1
Apple的UITextView在ivars前缀中使用m_。 - Christopher Lloyd

8

我遵循Chris Hanson的建议,在ivar前缀方面使用下划线,但我承认我也会在IBOutlets中使用下划线。然而,最近我开始将我的IBOutlet声明移动到@property行,按照@mmalc的建议。好处是所有我的ivar现在都有一个下划线,标准的KVC设置器被调用(即setNameField:)。此外,Interface Builder中的outlet名称没有下划线。

@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

1
这实际上是我现在所做的,感谢IB对属性的IBOutlet支持。 :) - Chris Hanson

3
您可以在ivar前使用下划线前缀,仍然可以使用非下划线名称作为属性名。对于合成的访问器,只需执行以下操作:
@synthesize foo = _foo;

这告诉编译器使用_foo实例变量来合成foo属性。

如果您编写自己的访问器,那么在实现中只需使用下划线ivar并保留非下划线方法名称即可。


2

个人而言,我遵循Cocoa命名规范,对于函数和变量使用驼峰命名法,对于对象名称使用大写的驼峰命名法(当然没有前缀NS)。

我发现类型前缀会使代码对于未编写它的人更加不透明(因为每个人都不可避免地使用不同的前缀),而在现代IDE中,很容易确定某些东西的类型,所以我不使用类型前缀。


2

随着属性的引入,我认为没有必要给类实例变量加上前缀“_”。您可以设置一个简单的规则(在头文件中描述),即任何要从类外部访问的变量必须通过属性访问,或者使用自定义方法来影响值。对我来说,这比在变量前面加上“_”名称要干净得多。它还可以适当地封装值,以便您可以控制它们如何更改。


1

虽然我喜欢在实例变量前使用下划线前缀,但我讨厌编写@synthesize行,因为它会导致很多重复(这不是很DRY)。我创建了一个宏来帮助解决这个问题并减少代码重复。因此,现在可以这样写:

@synthesize employee = _employee;

我写了这个:
ddsynthesize(employee);

这是一个简单的宏,使用标记粘贴将下划线添加到右侧:

#define ddsynthesize(_X_) @synthesize _X_ = _##_X_

唯一的缺点是它会混淆 Xcode 的重构工具,如果您通过重构重命名属性,它不会被重命名。

1

我的编程风格是混合的,实际上是PowerPlant时代的遗留物:

我最常用的前缀是“in”和“out”,用于函数/方法参数。这有助于您一眼了解参数的用途,并且真正有助于防止方法参数与实例变量之间的冲突(您有多少次看到参数“table”与同名的实例变量发生冲突)。例如:

- (void)doSomethingWith:(id)inSomeObject error:(NSError **)outError;

然后我在实例变量和属性名称中使用裸名:

然后我在本地变量前面加上“the”:theTable,theURL等。这有助于区分本地变量和实例变量。

然后按照PowerPlant的样式,我使用了一些其他前缀:k表示常量,E表示枚举,g表示全局变量,s表示静态变量。

我已经使用这种风格大约12年了。


不确定 k、E、g 和 s 的事情,但我喜欢添加输入和输出的想法。 - Steven Fisher

1
除了这里所说的,一定要阅读Cocoa文档中关于键值观察兼容命名的部分。严格遵循这个模式将有助于你在长期运行中获得巨大的帮助。

1

我不喜欢使用下划线作为任何标识符的前缀,因为C和C++都将某些下划线前缀保留供实现使用。

我认为使用"self.variable"很丑陋。

通常情况下,我使用未装饰的标识符(即没有前缀也没有后缀)作为实例变量。如果你的类太复杂以至于无法记住实例变量,那么你就有麻烦了。所以对于你的示例,我会使用"rect"作为实例变量的名称,"newRect"或"aRect"作为参数名称。


1

Andrew: 实际上有很多Cocoa开发者根本不使用实例变量前缀。在Smalltalk世界中,这也是非常普遍的(事实上,我会说在Smalltalk中几乎没有人在实例变量上使用前缀)。

对于实例变量的前缀,它总是让我想起C++,然后被带到Java和C#中。由于Objective-C世界与C++世界大致平行,而Java和C#世界则是其继承者,这就解释了你可能在不同开发者之间看到的“文化”差异。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接