以下人员在命名实例变量和方法参数时遵循哪些约定 - 特别是在使用方法参数设置ivars(实例变量)时?
在C ++中,我过去经常使用m_
前缀作为ivars。在C#中,我遵循了纯粹使用this.
用于ivars消除歧义的惯例。我已经采用了C ++中的等价物(this->
)。
在目标C中,我尝试了一些事情,但没有一个真的令人满意。
除非有人建议一些非常好的东西,否则我将不得不妥协(但请不要让我使用args的the
前缀!),所以我很感兴趣听听大多数人的意见 - 特别是那些一直使用ObjC的人。
我在发布此之前做了一些尽职调查,并在我找到了几个好的资源:
他们给了我一些想法,但我仍然希望听到别人在做什么。
[编辑] 只是为了澄清:特别是你如何区分ivars和我正在寻找的方法arg - 无论是通过前缀还是其他技术。
[编辑2]
感谢所有的回复和讨论要点。我没有关闭这个,但只是说,正如我在评论中对接受的答案所表明的那样,我已经采用了the
前缀init args的惯例(以及{{1}的setter args无论如何,我正在做的事情)。这似乎是力量的最佳平衡 - 即使我自己并不热衷于美学。
答案 0 :(得分: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在这种情况下会自动执行正确的操作,但您可能必须将_ivar
显式设置为支持)。
答案 1 :(得分:2)
以下是Apple does it。
的方式答案 2 :(得分:2)
要完成所有已知的Objective-C样式指针here,请使用google版本。他们所做的是在成员varname之后添加下划线。例如BOOL isActive_;
。
所以做出选择并坚持下去。我也更喜欢我的应用程序的“_”前缀。
答案 3 :(得分:1)
Apple生成的示例代码通常使用“_”前缀。我想我也看到一些使用mFoo
或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
如果您是(无论如何)。
答案 4 :(得分:1)
Obj-C并没有像许多其他语言那样严格定义“风格”,这可能是一件好事,或者说是一件坏事,但这意味着你可以在大多数时间内找到一个好的编码风格。
您也可以通过self访问Obj-C中的变量。因此,如果您有一个实例变量测试,您可以通过自我>测试访问它,这是合法的,并将始终有效。然而,在大多数Obj-C程序员看来,它并不美观。它给出了“秘密”,对象实际上只是结构(更准确地说,对象引用是结构的指针),实例变量实际上是结构成员。并不是说这是真的秘密,但是Obj-C程序员似乎更愿意在他们的代码中“隐藏”这个事实。
在名称中使用下划线“_”是一个非常糟糕的主意。这里有人指出,Apple为其代码保留了下划线,但实际上GCC已经为符号名称保留了下划线。更确切地说,ANSI-C标准已经规定,以两个下划线或一个下划线和大写字母开头的变量是为编译器的内部用法保留的。所以使用一个下划线在理论上是有效的,但是不小心用大写字母开头,它就变成了无效。
到目前为止,我尝试使用前缀my,myName而不是name,并使用前缀self,selfName而不是name;起初看起来有些奇怪,但在一大段代码中看起来并不太糟糕。至少立即击中眼睛“不同”。我也尝试了一个单独的“i”,iName而不是名字(或iname而不是name),但我对这个解决方案并不是很满意。
但是,我从未浪费时间考虑方法参数。因为它并不重要。这些变量与任何其他变量一样,除非它们被声明为常量。它们甚至可以在方法中重复用于其他目的,因为它对调用者没有任何影响。 E.g。- (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)。