15

对于实例变量和方法参数的命名,这里的人们遵循什么约定 - 特别是当方法参数用于设置 ivars(实例变量)时?

在 C++ 中,我经常使用m_ivars 的前缀。在 C# 中,我遵循纯粹通过使用this.for ivars 来消除歧义的约定。从那以后,我也采用了 C++ 中的等价物(this->)。

在 Objective C 中,我尝试了一些东西,但没有一个看起来真的令人满意。

除非有人提出非常好的建议,否则我将不得不妥协(但请不要让我使用theargs 的前缀!),所以我很想听听大多数人的意见 - 特别是来自那些已经使用 ObjC 一段时间的人。

在发布此内容之前,我做了一些尽职调查,并在其中找到了一些很好的资源:

他们给了我一些想法,但我仍然很想听听其他人在做什么。

[编辑] 澄清一下:这就是你如何区分 ivars 和我正在寻找的方法 args 的方式——无论是通过前缀还是其他一些技术。

[编辑 2] 感谢所有回复和讨论点。我没有结束这个,但我只想说,正如我在对已接受答案的评论中指出的那样,我已经采用了在 init args 前加上前缀的约定the(以及在 setter args 前加上new,无论如何我都在这样做)。这似乎是力量的最佳平衡——即使我自己并不热衷于美学。

4

5 回答 5

17

正如您所指出的,Cocoa 风格是使用方法参数名称,例如theValue参数名称是否会与实例变量冲突。然而,这在 Objective-C 2.0 风格的代码中应该不会出现很多次。假设是您不应该(通常)直接访问实例变量。这主要是因为这样做绕过了 Cocoa 中的 Key-Value Observing 机制。相反,期望是您将通过 getter/setter 方法访问和改变属性。在 Objective-C 2.0 中,很容易声明这些属性并自动@synthesize生成 getter/setter,因此没有太多理由不使用它们。事实上,在 64 位系统上,运行时会自动为您创建实例变量,无需声明它们并减少使用它们的冲动。

您应该直接访问实例变量的唯一一次是在-init-dealloc方法中:

@interface MyObject : NSObject 
{
  id ivar;
}

@property (retain,readwrite) id ivar; //or whatever retain/copy/assign and read/readwrite makes sense
@end

@implementation MyObject
@synthesize ivar;

- (id)initWithIvar:(id)theIvar {
  if(self = [super init]) {
    ivar = theIvar;
  }

  return self;
}

- (void)dealloc {
  [ivar release];
}

在这些情况下应该直接使用 ivar 的原因是因为 getter/setter 可能具有依赖于完全初始化的实例的副作用,从而使它们在对象的状态完全初始化-init-dealloc地方很危险。在所有其他情况下,您应该使用self.ivar(或[self ivar][self setIvar:newValue])。

似乎其他方法不-initWithXX应该有命名冲突。如果他们这样做了,不应该将它们重构为没有该参数或让 Class 没有实例变量吗?

这仅留下-initWithXX您经常会在参数和 ivars 之间发现冲突的方法。对于这种情况,如果您真的无法忍受 Cocoa 风格,您可以使用您提到的任何方法。以_作品为前缀并且相对常见(我相信@synthesize'd setter 和 getter 在这种情况下会自动做正确的事情,但您可能必须明确地将 the 设置_ivar为支持)。

于 2009-02-15T05:19:50.107 回答
2

在这里完成所有已知的 Objective-C 样式指南是 google 版本。他们所做的是在成员 varname 之后添加下划线。例如BOOL isActive_;.
所以做出选择并坚持下去。我也更喜欢我的应用程序的“_”前缀。

于 2009-02-16T07:05:03.297 回答
1

以下是Apple 的做法

于 2009-02-14T23:37:00.290 回答
1

Apple 制作的示例代码通常使用“_”前缀。我想我也看到了一些使用mFooor m_foo。有些人根本不关心前缀,只使用普通名称,但是稍后会变得混乱。通常在定义方法参数时,命名约定是使用“a”、“an”、“the”或“new”前缀。例如:

@interface Foo : NSObject {
    id _bar;
}
@property (nonatomic, retain) id bar;

- (id) initWithBar:(id)aBar;

@end

@implementation Foo
@synthesize bar = _bar;

- (id) initWithBar:(id)aBar {
    self = [super init];
    if(self != nil) {
        _bar = aBar;
    }
    return self;
}

@end

我发现这个约定很好用。我以前不关心前缀,但这有时会让事情变得混乱。使用前缀清楚地表明它是一个实例变量。Apple 在其 (iPhone) 示例代码中使用了该@synthesize bar = _bar约定。

无论如何,通常不会使用实例变量,因此如果您发现“_”前缀令人讨厌,那也没关系,因为无论如何您都会使用[self bar](或者self.bar如果您喜欢那种东西)。

于 2009-02-15T06:19:44.113 回答
1

Obj-C 并没有像许多其他语言那样严格地定义“风格”,这可能是一件好事,也可能是一件坏事,但这意味着你大部分时间都需要靠自己找到一种好的编码风格。

您还可以通过 self. 因此,如果您有一个实例变量 test,您可以通过 self->test 访问它,这是合法的并且将始终有效。不过,在大多数 Obj-C 程序员眼中,它并不漂亮。它泄露了“秘密”,即对象实际上只是结构(更准确地说,对象引用是指向结构的指针),而实例变量实际上是结构成员。并不是说这真的是秘密,但 Obj-C 程序员似乎更喜欢在他们的代码中“隐藏”这个事实。

在名称中使用下划线“_”是一个非常糟糕的主意。这里有人指出,Apple 为他们的代码保留了下划线,但实际上 GCC 已经为符号名称保留了下划线。更准确地说,ANSI-C 标准已经规定以两个下划线或一个下划线和一个大写字母开头的变量保留供编译器内部使用。所以使用一个下划线在理论上是有效的,但是不小心以大写字母开头的名字就失效了。

到目前为止,我尝试使用前缀 my, myName 代替 name,并使用前缀 self, selfName 代替 name;起初看起来都有些奇怪,但在一大段代码中看起来并不算太糟糕。至少立即引起了人们的注意,因为它是“不同的”。我也只是尝试了一个“i”,用 iName 代替 name(或用 iname 代替 name),但我对那个解决方案不是很满意。

不过,我从来没有浪费时间考虑方法参数。因为这并不重要。这些变量与任何其他变量一样,除非它们被声明为常量。它们甚至可以在方法中重新用于其他目的,因为它不会影响调用者。例如

- (NSImage *)loadImage:(int)imageNumber
{
  NSImage * res;

  // Some code that assigns a value to res
  // ...  

  // Re-use imageNumber for a different purpose
  for (imageNumber = 0; ...; ...) {
     // Some code
  }

  return res;
}

我认为该代码没有问题。只要名称仍然有意义,为什么我必须为此声明第二个堆栈变量(如果我没有在 for 循环中按数字迭代图像,那么名称当然没有意义,在这种情况下我会使用一个不同的变量 - 编译器实际上可能只为两者保留一个 int 堆栈)。

于 2009-12-09T15:02:42.900 回答