开发者

What are your naming conventions for Objective-C "private" methods?

开发者 https://www.devze.com 2023-03-01 05:23 出处:网络
Inheriting code from other developers has made me a firm believer in keeping as many messages as possible out of a class\' public interface by means of a Class Extension. I\'m also a firm believer in

Inheriting code from other developers has made me a firm believer in keeping as many messages as possible out of a class' public interface by means of a Class Extension. I'm also a firm believer in adopting special naming conventions for private, implementation-specific members of a class. I really like being able to tell at a glance what messages being sent and what members being referenced within the implementation context are not ever intended for public use and vice versa. If nothing else, it makes the overall semantics of a class easier for me grasp more quickly, and that's wor开发者_运维技巧th it.

Justification aside, I've written boatloads of classes with boatloads2 of private methods, but I've never really come up with a pattern for naming that I really love (like I do the controversial ivar_ convention for ivars). Notable examples:

@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

At this point, there are a kajillion different means by which I could mangle my private method names, but instead of making something up, I figured I would first take a poll for any popular conventions I may not be aware of. So, what have you used?


I don't distinguish private methods by name. Instead, I keep them out of the public interface by declaring them in the class extension portion of the .m file, thus:

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


I use double underscore for my private methods:

- (void)__doSomethingPrivate;

It almost looks like the single underscore-syntax (good readable) and at the same time confirms to the Apple guides.


I use a prefix, no underscore. The prefix is generally related to the name of the project in question. If you do use underscores, there's no need to have more than one.


I use two levels of private methods: slightly private and very private. Slightly private methods are methods which could become public, but currently aren't. They are usually convenience methods that I use internally, and I usually don't put in as much protection unless I decide to make it public. For very private methods, I ignore apple and use an underscore prefix. Since 99% of my code is in classes I create and I usually have prefixes on my class names, the chances of running into naming problems is small. When adding code to classes I didn't make, I rarely make private methods, but add a short prefix on the rare occasion that I do.


I prefix private methods with a 'p':

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

Similarly, I use 's' for static (or class) methods:

  • (Universe*)sGet; // used to return singleton Universe object.

Beyond naming conventions, I declare private methods in .m files instead of .h files.


Using a fixed prefix will help to "hide" the method from the outside world but it won't prevent a method from being accidentally overridden. E.g. I once extended a class and I made a method:

- (void)private_close
{
    // ...
}

The result was that the behavior of the class broke in horrible ways. But why? It turned out, the super class also had a method name private_close and I was accidentally overriding it without calling super! How should I know? No compiler warning!

No matter if your prefix is _ or __ or p or private_, if it is always the same, you will end up with problems like this one.

So I prefix private methods (and properties!) with a prefix that resembles the class name. Therefor I take the upper case letters of the class name to form the "private prefix":

  • ComplexFileParser -> CFP
  • URLDownloadTask -> URLDT
  • SessionController -> SC

This is still not perfectly safe, yet it is very unlikely that a subclass with a different name has the same still the same private prefix.

Also when you do frameworks, you should prefix all classes and other symbols with a framework prefix (as Apple does with NS..., CF..., CA..., SC..., UI..., etc.) and thus this class prefix is part of the private prefix as well making collisions even less likely:

  • Framework DecodingUtils.framework -> DU
    • Class ComplexFileDecoder in framework -> DUComplexFileDecoder
      • Private Prefix -> DUCFD
        • Private Method close -> - (void)DUCFD_close

Alternatively append the prefix at the end of the fist method argument name, to get better auto-completion:

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

will become

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

or always only append it to the last parameter name:

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

or (now it gets really crazy) - add a fake dummy parameter just for naming:

- (void)doSomethingWith:(Type1)var1 parameters:(Type2)var2 DUCFD:(id)x

where x is actually never used in the method and you pass nil for it:

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

and as it will always be the same at the end, use a pre-processor macro:

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

// ...

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

Prefix and suffixing works also with properties (and thus their ivar, getter/setter methods), the preproessor trick above won't, of course.


Regarding Apple recommendations. You might be interested in how Apple writes it's own code.

If you check private APIs you will see that they use underscores for private methods everywhere. Every peace of Obj-C code in iOS uses them. And in many cases those methods go through multiple iOS versions without refactoring or renaming which means it's not a temporary solution for them but rather a convention. In fact, there're three levels of private methods they use extensively - no underscore, single and double underscore.

As for other solutions like "private", class or project name prefixes - they don't use them at all. Just underscores.

0

精彩评论

暂无评论...
验证码 换一张
取 消