My Cocoa Coding Style
最近回頭看我第一個比較成功的軟體 Nally,發現以前實在是不懂事啊。沒有 profile 過 bottle-neck 就擅自想:「我只要把所有的地方都寫得有效率就好了!」,結果證明 Knuth 是對的:「Premature Optimization is EVIL」。結果就是,寫得很醜又難懂。
後來在一些新的 project 上我已經採用了新的 coding style,目前使用上已經穩定下來了。自己有一套原則後,在幫別人看 code 抓漏時只要沒有 consistent coding style 都會讓我很難過。所以,請大家自己也設定一套 coding style 吧。不要有的時候 if 和 ( 中間有空格,有時沒空格的。
Header File:
extern int YLSomeConstant; @interface YLMyClass : NSObject { // Prefix your class by abbreviation NSString *_name; // prefix instance variable with underscore BOOL _beta; IBOutlet NSView *mMyView; // prefix IBOutlet with m } @property (copy) NSString *name; @property BOOL beta; /* space between each token except the argument and its type */ - (void) methodDeclaration: (TypeClass *)arg1 anotherArgument: (id)arg2; @end
在一般變數命名上和大家都差不多,值得注意的是我使用了 Apple 叫你不要用的 prefix 命名系統。重點不在你要隱藏什麼,而是之後你可以明顯看出,一個變數到底是 ivar 還是只是 local variable。排版方面我喜歡較寬鬆的版型,所以 method declaration 除了 argument 與其型別之間一律空一格。雖然這樣讓我沒辦法直接用 Apple 生成的 code 或者從文件中拷貝過來就可以用,但是看起來舒服些。
Implementation File:
int YLSomeConstant = 18; static CGSize gMySize; // prefix static variable with g @interface YLMyClass (Private) - (int) _ageOfWoman; // prefix private method with underscore @end @implementation YLMyClass (Private) - (int) _ageOfWoman { return YLSomeConstant; } @end @implementation YLMyClass - (YLMyClass *) init { if ([super init]) { // Not (self = [super init]) // initialize code } return self; } - (void) methodDeclaration: (TypeClass *)arg1 anotherArgument: (id)arg2 { if (!arg2) return; // short statement takes one line if (![arg1 sendSomeMessage: _name withData: [NSData data]]) return; // long statement takes two lines int i; // local variable, no prefix for (i = 0; i < 100; i++) { // Loop here. while, do while follow the same style. } switch (c) { case 1: // code case 2: // code default: // code } } @end
而我的 private method 前面也加了底線,雖然這可能會 override Apple 的 private method,但是我沒辦法忍受 YL_thisIsAPrivateMethod 這麼醜陋的寫法。這是從 Wil Shipley 那邊學來的。
而我的 accessor 寫法是這樣的:
- (SomeClass *) myProperty { return [[_myProperty retain] autorelease]; } - (void) setMyProperty: (SomeClass *)aProperty { if (_myProperty != aProperty) { [_myProperty release]; _myProperty = [aProperty retain]; } }
自己內部使用時,_myProperty 絕對是唯獨的。要存取一定得叫用 setter。至於 getter 這樣寫是為了避免直接回傳會發生這種情況:
id aProperty = [someObj myProperty]; // assume [aProperty retainCount] == 1 [someObj setMyProperty: anotherProperty]; // aProperty was dealloc'd now! [aProperty doSomething]; // Crash!

“雖然我在寫別的語言,不過我除了左大括跟你不一樣以外,其它的 style 不約而同
”
---ericsk. 12/30, 2008