你们在Objective-C中“私有”方法的命名规范是什么?

20
从其他开发者那里继承代码让我坚信通过类扩展尽可能减少公共接口中的消息数量是非常必要的。我也坚信采用特殊的命名约定来区分类的私有成员和实现特定的成员。我真的很喜欢一眼就能看出在实现上下文中发送了哪些消息,引用了哪些成员,它们都不是为公共使用而设计的,反之亦然。如果没有其他什么,这使得我更快地理解一个类的整体语义,这是值得的。

抛开理由不谈,我写了大量带有大量私有方法的类,但我从未真正想出一种我真正喜欢的命名模式(就像我对于ivars的有争议的ivar_约定一样)。值得一提的例子:

@interface myClass()

// I like this, but as we all know, Apple has dibs on this one, 
// and method name collisions are nasty.
- (void)_myPrivateMessage;

// The suffix version promoted by Google for ivars doesn't really translate
// well to method names in Objective-C, because of the way the method
// signature can be broken into several parts.
- (void)doWork_; // That's okay...
- (void)doWork_:(id)work with_:(id)something; // That's just ugly and tedious...
- (void)doWork_:(id)work with_:(id)something and_:(id)another; // My eyes...

// This version is suggested by Apple, and has the benefit of being officially 
// recommended. Alas, I don't like it: The capital letter is ugly. I don't like 
// underscores in the middle of the name. Worst of all, I have to type three characters 
// before code-sense does anything more useful than inform me that I am typing.
- (void)BF_doWork;

@end

目前有很多不同的方法可以混淆我的私有方法名称,但是我并不想自己编造,所以我想首先询问一下是否存在任何我不知道的流行惯例。那么,你用过什么呢?

7个回答

9

我不通过名称区分私有方法。相反,我通过在.m文件的类扩展部分中声明它们来将它们排除在公共接口之外,如下所示:

@interface MyClass ()
- (void)doWork;
@end

1
没错,这是声明私有方法的正统方式。我也是这么做的。对我来说,命名惯例并不是我想要在头文件中区分公有方法和私有方法名称的东西,它仅仅是为了在实现文件中更易于读懂。我已经编辑了问题以澄清,抱歉造成的混乱 =) - Matt Wilding
我猜如果命名对于你来说很重要以便做出区分的话,那么你的类就太大了。:-) 正如Bob大叔所说,“还有另一个类想要诞生”。 - Jon Reid
2
嘿,是的,我认为这可能是我听到的一个意见。我完全同意庞大的类是不好的,应该避免使用。但即使对于一个只有5个方法的类,其中只有两个是私有的,我发现当我在创作日期6个月后回过头来看它时,仅仅通过查看就能明确语义,而不必浪费额外的半秒钟和精力移动我的眼球。也许我有点懒 =) - Matt Wilding
现在对这个对象进行子类化,并让它的子类也声明一个私有方法doWork...会发生什么?好吧,它会覆盖其父类的doWork。哎呀,这可能不是预期的结果。 - Mecki
@Mecki:有趣。但是命名约定并不能解决这个问题,因为Objective-C没有真正的私有方法。 - Jon Reid

7

我使用双下划线来表示我的私有方法:

- (void)__doSomethingPrivate;

它几乎看起来像单下划线语法(易读性高),同时也符合苹果指南的规范。

1
以双下划线开头的内容根据定义也会以单下划线开头,因此我不确定这是否符合苹果的指南。 - honus

4

我使用前缀,而非下划线。通常,这个前缀与相关项目的名称有关。如果您确实使用下划线,那么没有必要多于一个。


3

我使用两种级别的私有方法:略微私有和非常私有。略微私有的方法是指可能成为公共方法,但目前不是。它们通常是我在内部使用的方便方法,除非我决定将其公开,否则我通常不会加入太多的保护措施。对于非常私有的方法,我忽略了苹果公司的建议并使用下划线前缀。由于我创建的类中有99%的代码,并且我通常在类名中使用前缀,因此遇到命名问题的几率很小。当向我未创建的类添加代码时,我很少使用私有方法,但在极少数情况下会添加一个简短的前缀。


我也长期以来一直是“忽略苹果自定义类”的支持者,直到我的良心最终战胜了我。我当然喜欢它... - Matt Wilding
5
“大多私人”和“全部私人”之间有很大的区别。你知道,“大多私人”的话,它们是“稍微公开”的。但是,“全部私人”呢,通常只有一件事情可做。” - jscs
@Josh 你非得把整个东西都变成链接吗?这样在iPad上想要点赞就很难了,因为它会认为我想点击链接而不是旁边的空白处。 - ughoavgfhw
抱歉,这是我在这里看到的做法。记住了,很高兴你喜欢! - jscs
1
@Josh 你可能应该链接整个东西,我只是开玩笑,虽然我不小心点击了链接,想要一个箭头。 - ughoavgfhw
为了增加对未来访问者的讨论:忽略苹果公司自定义类可能行不通,因为从技术上讲,任何自定义类都只是NSObject子类。你可能会意外地覆盖一个内部NSObject方法。这不太可能发生,除非你使用一个明显宽泛的名称,但仍有可能。 - Dev Kanchen

1

我会在私有方法前加上“p”前缀:

  • (void) pDoWork;
  • (void) pDoWork:(id)work with:(id)something;

同样地,我使用“s”来表示静态(或类)方法:

  • (Universe*)sGet; // 用于返回单例 Universe 对象。

除了命名约定外,我会在 .m 文件中声明私有方法而不是 .h 文件中。


我肯定可以澄清一下,我已经声明了一个类扩展中的私有方法。我想这很容易被忽略。我编辑了问题以澄清,感谢您的建议。 - Matt Wilding

1
使用固定前缀可以帮助“隐藏”方法,使其不受外界干扰,但这并不能防止方法被意外覆盖。例如,我曾经扩展了一个类,并创建了一个方法:
- (void)private_close
{
    // ...
}

结果是类的行为以可怕的方式变坏了。但是为什么呢?原来,超类也有一个名为private_close的方法,而我无意中重写了它而没有调用super!我怎么知道呢?没有编译器警告!
无论您的前缀是___p还是private_,如果始终相同,您最终都会遇到这样的问题。
因此,我使用一个类似类名的前缀来前置私有方法(和属性!)的名称。因此,我使用类名的大写字母来形成“私有前缀”:
  • ComplexFileParser -> CFP
  • URLDownloadTask -> URLDT
  • SessionController -> SC
这仍然不是完全安全的,但非常不可能存在一个具有不同名称的子类与相同的私有前缀。
此外,当您使用框架时,应该为所有类和其他符号添加一个框架前缀(就像Apple公司使用的NS...CF...CA...SC...UI...等),因此这个类前缀也是私有前缀的一部分,使冲突的可能性更小:
  • 框架DecodingUtils.framework -> DU
    • 在框架中的类ComplexFileDecoder -> DUComplexFileDecoder
      • 私有前缀 -> DUCFD
        • 私有方法close -> - (void)DUCFD_close

或者将前缀附加到第一个方法参数名称的末尾,以获得更好的自动完成:

- (void)doSomethingWith:(Type1)var1 parameters:(Type2)var2

将变成

- (void)doSomethingWith_DUCFD:(Type1)var1 parameters:(Type2)var2

或者总是将它附加到最后一个参数名称:
- (void)doSomethingWith:(Type1)var1 parameters_DUCFD:(Type2)var2

或者(现在变得非常疯狂)- 添加一个虚假的假参数只用于命名:
- (void)doSomethingWith:(Type1)var1 parameters:(Type2)var2 DUCFD:(id)x

其中x在该方法中实际上从未被使用,您需要将其传递为nil

[self doSomethingWith:var1 parameters:var2 DUCFD:nil];

由于最终结果始终相同,因此请使用预处理器宏:

#define priv DUCFD:nil
#define PRIVATE DUCFD:nil

// ...

[self doSomethingWith:var1 parameters:var2 priv];
[self doSomethingWith:var1 parameters:var2 PRIVATE];

前缀和后缀也适用于属性(以及它们的ivar、getter/setter方法),上面的预处理器技巧当然不适用。

0
关于苹果的建议。您可能会对苹果如何编写自己的代码感兴趣。
如果您检查私有API,您会发现它们在私有方法中使用下划线。iOS中的每个Obj-C代码都使用它们。在许多情况下,这些方法经过多个iOS版本而没有重构或重命名,这意味着它们不是临时解决方案,而是一种约定。实际上,他们广泛使用三个级别的私有方法-无下划线、单下划线和双下划线。
至于其他解决方案,如“private”、类或项目名称前缀-他们根本不使用。只有下划线。

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