4

作为 Objective-C(但长期 C/++)程序员的新手,我正在寻找有关变量命名约定的建议/建议。

我个人的偏好是为实例变量使用前缀,这既是为了在函数中清晰,又是为了防止函数参数的阴影。但是,我喜欢排除前缀的属性(除非您还为属性名称添加前缀,这不能很好地工作并且看起来很愚蠢)。同样,我可以使用“self.variable”约定,但前提是我将所有内容都设为属性。

那么,鉴于下面的代码,您对实例/函数变量的首选命名风格是什么?如果你不打扰,你如何处理函数参数上的阴影?

@interface GridItem : NSObject
{
    CGRect _rect;
    ...  
}
@end

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

干杯!

4

10 回答 10

15

大多数 Cocoa 项目使用下划线作为非IBOutlet实例变量前缀,并且不使用实例变量前缀IBOutlet

我不使用下划线作为IBOutlet实例变量的原因是,当加载 nib 文件时,如果您有一个用于连接的插座的 setter 方法,则将调用该 setter。 然而,这种机制不使用键值编码,因此不会设置名称以下划线 ( eg _myField )为前缀的 IBOutlet,除非设置器的名称与插座 ( eg ) 完全相同,这是非标准且粗略的。 set_myField:

另外,请注意,使用类似self.myProp的属性访问实例变量不同。当您使用属性时,您正在发送消息,就像您使用括号表示法一样[self myProp]。所有属性所做的就是为您提供简洁的语法,以便在一行中指定 getter 和 setter,并允许您综合它们的实现;它们实际上并没有使消息分发机制短路。如果你想直接访问一个实例变量但在它前面加上self你需要把它self当作一个指针来对待,就像self->myProp它实际上是一个 C 风格的字段访问一样。

最后,在编写 Cocoa 代码时不要使用匈牙利符号,并避免使用其他前缀,如“f”和“m_”——这会将代码标记为由不“明白”的人编写,并会导致它被其他 Cocoa 开发者怀疑。

一般来说,遵循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

您会看到我在我的and方法中使用了Employee直接引用 an 的实例变量,而我在其他方法中使用了该属性。这通常是一个很好的属性模式:只在初始值设定项、 in以及属性的 getter 和 setter 中触及属性的底层实例变量。-init-dealloc-dealloc

于 2008-08-15T05:32:40.293 回答
8

我遵循 Chris Hanson 关于下划线 ivar 前缀的建议,尽管我承认我也确实将下划线用于 IBOutlets。但是,根据@mmalc 的建议,我最近开始将我的IBOutlet声明移到该@property行。好处是我所有的 ivars 现在都有一个下划线,并且标准的 KVC 设置器被称为(即)。此外,接口生成器中的插座名称没有下划线。setNameField:

@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
于 2008-11-10T16:31:11.157 回答
3

您可以在您的 ivars 上使用下划线前缀,并且仍然为您的属性使用非下划线名称。对于合成访问器,只需执行以下操作:

@synthesize foo = _foo;

这告诉编译器使用 the_foo ivar 合成 foo 属性。

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

于 2008-09-15T16:20:12.153 回答
2

就个人而言,我遵循 Cocoa 命名约定,对函数和变量使用驼峰式大小写,对对象名称使用大写驼峰式大小写(当然没有前导 NS)。

我发现类型前缀使代码对不编写它的任何人都更加不透明(因为每个人总是使用不同的前缀),并且在现代 IDE 中找出某些东西的类型并不是那么困难。

于 2008-08-13T20:38:36.397 回答
2

随着属性的引入,我认为无需在类实例变量前加上“_”前缀。您可以设置一个简单的规则(在您的头文件中描述),任何要在类外部访问的变量都必须通过属性访问,或者通过使用类上的自定义方法来影响值。这对我来说似乎比在他们前面贴上“_”的名字要干净得多。它还正确封装了这些值,以便您可以控制它们的更改方式。

于 2008-09-15T06:00:54.000 回答
1

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

我认为使用“self.variable”是丑陋的。

通常,我对实例变量使用朴素的标识符(即没有前缀或后缀)。如果你的类太复杂以至于你不记得实例变量,你就有麻烦了。因此,对于您的示例,我将使用“rect”作为实例变量的名称,并使用“newRect”或“aRect”作为参数名称。

于 2008-08-13T20:36:32.877 回答
1

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

实例变量的前缀总是让我觉得是一种 C++ 主义,它被带到 Java 和 C#。由于 Objective-C 世界在很大程度上与 C++ 世界平行,而 Java 和 C# 世界是它的继承者,这可以解释您在不同开发人员之间可能会看到的“文化”差异。

于 2008-08-15T05:36:36.043 回答
1

我的风格是混合的,实际上是 PowerPlant 时代的延续:

我使用的最有用的前缀是函数/方法参数的“in”和“out”。这可以帮助您一目了然地了解参数的用途,并且确实有助于防止方法参数和实例变量之间发生冲突(您见过多少次参数“表”与同名的实例变量冲突)。例如:

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

然后我将裸名称用于实例变量和属性名称:

然后我使用“the”作为局部变量的前缀:theTable、theURL 等。这再次有助于区分局部变量和实例变量。

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

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

于 2008-10-01T14:46:47.170 回答
1

虽然我喜欢为 ivars 使用下划线前缀,但我讨厌写@synthesize行,因为所有的重复(它不是很)。我创建了一个宏来帮助做到这一点并减少代码重复。因此,而不是:

@synthesize employee = _employee;

我写这个:

ddsynthesize(employee);

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

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

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

于 2008-11-10T16:37:38.727 回答
1

除了这里所说的,请务必阅读 Cocoa 文档中关于 Key Value Observing 兼容命名的内容。从长远来看,严格遵循这种模式将对您有很大帮助。

于 2008-11-17T21:21:30.377 回答