注意事項
顯示在本指南中的隱藏細節
這個風格指南包含很多最初不可見的細節。它們被標記為三角形圖標,你可以在左邊看到。現在點擊它,你應該會看到“萬歲”出現在下面。
背景
Objective-C是一種很動態的、面向對象的C語言擴展。它被設計成易用易讀,同時支持復雜的面向對象設計。它是Mac OS X和iPhone上開發新應用的主要開發語言
Cocoa是在Mac OS X平台上的一個主要的應用框架。這是一個提供給全功能Mac OS X應用程序的快速開發的Objective-C類集合。
Apple已經為Objective-C編寫了一本很好的、被廣泛接受的編碼指南;Google也為C++寫了一本類似的指南。這本Objective-C指南意在成為一個對Apple和Google的一般建議的自然組合。因此,在讀這本指南之前,確定你已經度過:
Apple的Cocoa編碼指南
Google的開源C++設計指南
注意:所有在Google C++指南中禁用的在Objective-C++裡也一樣,除非本文特別指出。
這個文檔是為了描述用於所有Mac OS X代碼中的Objective-C(和Objective-C++)編碼指南和實踐的。這些指南的很多地方已經進化並在其他項目和團隊已經過時。谷歌開發的開源項目符合本指南中的要求。
谷歌已經發布了符合這些准則的,作為Mac項目的谷歌工具箱(以下簡稱GTM)的一部分的開源代碼。意味著要在不同項目共享的代碼是一個包含在這個庫中很好的候選。
注意:這本指南不是一個Objective-C教程。我們假設讀者對這麼語言很熟悉。如果你是一個Objective-C初學者或需要復習,請閱讀的Objective-C編程語言這本書。
例子
他們說一個例子勝過千言萬語,讓我們開始用一個例子讓你感受Objective-C的風格,間距,命名等。
一個頭文件的例子,展示了@interface聲明的正確注釋和間距:
01 #import <Foundation/Foundation.h>
02
03 // A sample class demonstrating good Objective-C style. All interfaces,
04 // categories, and protocols (read: all top-level declarations in a header)
05 // MUST be commented. Comments must also be adjacent to the object they're
06 // documenting.
07 //
08 // (no blank line between this comment and the interface)
09 @interface Foo : NSObject {
10 @private
11 NSString *_bar;
12 NSString *_bam;
13 }
14
15 // Returns an autoreleased instance of Foo. See -initWithBar: for details
16 // about |bar|.
17 + (id)fooWithBar:(NSString *)bar;
18
19 // Designated initializer. |bar| is a thing that represents a thing that
20 // does a thing.
21 - (id)initWithBar:(NSString *)bar;
22
23 // Gets and sets |_bar|.
24 - (NSString *)bar;
25 - (void)setBar:(NSString *)bar;
26
27 // Does some work with |blah| and returns YES if the work was completed
28 // successfully, and NO otherwise.
29 - (BOOL)doWorkWithBlah:(NSString *)blah;
30
31 @end
一個源文件的例子,展示了一個接口的@implementation的正確注釋和間距。它也包含一些重要方法,像getters、setters、init和dealloc的參考實現: 01 #import "Foo.h"
02
03
04 @implementation Foo
05
06 + (id)fooWithBar:(NSString *)bar {
07 return [[[self alloc] initWithBar:bar] autorelease];
08 }
09
10 // Must always override super's designated initializer.
11 - (id)init {
12 return [self initWithBar:nil];
13 }
14
15 - (id)initWithBar:(NSString *)bar {
16 if ((self = [super init])) {
17 _bar = [bar copy];
18 _bam = [[NSString alloc] initWithFormat:@"hi %d", 3];
19 }
20 return self;
21 }
22
23 - (void)dealloc {
24 [_bar release];
25 [_bam release];
26 [super dealloc];
27 }
28
29 - (NSString *)bar {
30 return _bar;
31 }
32
33 - (void)setBar:(NSString *)bar {
34 [_bar autorelease];
35 _bar = [bar copy];
36 }
37
38 - (BOOL)doWorkWithBlah:(NSString *)blah {
39 // ...
40 return NO;
41 }
42
43 @end
在@interface、@implementation和@end前後的空行是可選的。如果你的@interface聲明了實參,那麼右括號之後需要有一個空行。
除非interface或implementation很短,比如,當定義一小部分私有方法或一個橋接類時,添加空行通常有利於可讀性。
間距和格式
空格(spacing)與制表符(tab)
▶
僅使用空格,每次縮進2個空格。
每行的寬度
▶
應盡量在你的代碼中將每行控制在80個字符內。
方法的聲明和定義
▶
在-(或+)與返回值類型中間須要有一個空格,在參數列表中,除了參數之間不要有任何間距。
方法調用
▶
方法調用的格式須要與定義時個格式一致。當有多種格式化的樣式可供選擇的時候,按照慣例,采用在給定的源文件中使用過的那個方式。
@public與@private
▶
@public與@private訪問修飾符後邊須要有一個空格。
Exceptions
▶
在單獨一行時,使用 @ 標簽格式化 exceptions,@ 標簽和開放括號 ({) 間加一個空格,在@catch 和 對象捕獲聲明之間也是。
Protocols
▶
在類型標識符和封裝在尖括號中的 Protocols 名稱之間不應該有空格。
Blocks
▶
Blocks 在創建回調函數時更傾向於目標選擇器模式,這可以讓代碼更易讀。塊內的代碼應縮進4個空格。
命名
命名規則對於代碼的可維護性是非常重要的。Objective-C的方法命名趨向於超長命名,但這會帶來良好的代碼閱讀感受,就像讀散文一樣,同時還避免了很多不必要的注釋。
在撰寫純粹的Objective-C代碼時,我們主要是遵循標准的Objective-C命名規范。這些命名方針可能和C++的命名規范相去甚遠。比如,Google的C++規范中推薦在變量名中的單詞間使用下劃線,而Objective-C的規范推薦使用駝峰命名法,這也是在Objective-C社區中的標准做法。
任何類、目錄、方法或者變量的名字都應該將其中的首字母縮略詞設為大寫。下面是蘋果官方使用的大寫的首字母縮略詞:URL,TIFF和EXIF。
然而,在編寫Objective-C++代碼時,往往並非能完全按照規范來進行。很多項目會使用Objective-C,或是Cocoa,或是C++後端與原生的Cocoa前端通信的方式來實現跨平台的C++ API。這就導致了兩種語言規范直接沖突的情況。
我們的解決方法是依據方法/函數具體實現的方式來決定命名。如果你在一個@implementationblock裡面,就使用Objective-C的命名規范。如果你在一個C++類裡面實現一個方法,就使用C++命名規范。這就避免了在一個函數中實例變量和本地變量的命名規則混合使用的情況,減少了對代碼的可閱讀性造成的極大損害。
文件名
▶
文件名應該反映其中包含的類實現的名稱,按照你項目中的約定且大小寫相關。
Objective-C++
▶
在一個源碼文件中, Objective-C++ 遵循你實現的函數/方法的風格。
類名
▶
類名(類別和協議名稱)應為大寫,並開始使用大小寫混合以區分單詞。
分類名稱
▶
分類名稱應該以一個2到3個字母的前綴開始,識別分類是項目的一部分,還是打開使用。分類,名稱應該結合它擴展的類的名稱。
Objective-C 方法名稱
▶
方法名稱應該以小寫字母開頭,混合大小寫。每個命名參數也應該以小寫字母開頭。
變量名
▶
變量名以小寫字母開頭,混合大小寫以區分單詞。實例變量以下劃線開頭。例如:myLocalVariable,_myInstanceVariable。
注釋
盡管寫的時候很痛苦,但是他們對於保持你代碼的可讀性來說絕對是至關重要的。下面幾條規則描述了你應該什麼時候在什麼地方加注釋。但是要記住,雖然注釋很重要,但是最好的代碼都是自注釋的。給變量和類型一個有意義的名字,要比用一個難懂的名字然後再費力的用注釋來解釋好得多。
寫注釋的時候,要寫給你的讀者:下一個要讀懂你代碼的貢獻者。多寫點吧——下個沒准就是你自己!
記住所有c++編程規范裡列出的規則和協定在這裡也是生效的,下面是幾點補充。
File Comments文件注釋
▶
可以有選擇的在一個文件開頭寫一段關於內容的描述。
聲明注釋Declaration Comments
▶
每個接口,類別,協議的聲明都應該有個伴隨的注釋,來描述他的作用以及他如何融入整體環境。
實現聲明Implementation Comments
▶
用豎向排列方式在注釋中引用變量名和符號,不要寫成一整行。
對象所有權Object Ownership
▶
指針所有權模型超出了常見的 Objective-C用法時,將他的描述寫的越詳細明了越好。
Cocoa和Objective-C的特性
被申明在頭文件的變量必須是私有的
當變量被申明在頭文件時,這個變量必須被標記為@private
標識初始化器
要描述或者標識好初始化器
重寫初始化器
當你寫一個包含init()方法的的子類時,一定要確定重寫了父類的初始化器
重寫NSObject方法的位置
強連建議將重寫NSObject的方法放到@implementation注記的上面
初始化
不要在init方法中把變量初始化為0或者nil,這樣做完全是多余的
避免處理new方法
不要嘗試調用NSObject類的new()方法,也不要在他的子類中復寫這個方法。我們可以利用他的init方法來實例化這些保留對象
保持公有API簡單
要保持你的類盡量簡單:避免過分渲染APIs.如果有的方法沒必要公開,那就不要公開.要利用private去避免把公有頭弄得雜亂
#import 和 #include
要引入Objective-C/Object-C++頭文件時用#import;要引入C/C++頭文件時用#include.
利用跟框架
在獨立文件之上應該包含跟框架
創建完了即可銷毀釋放
當創建一些臨時對象時,在創建的那一行銷毀並釋放比在同一個方法內下創建然後過一會兒銷毀更好
釋放並保留
對象的業務遵循釋放並保持規則
在執行init或者dealloc方法時避免訪問器
當init和dealloc方法正在執行時,子類的實例化可能處在一個不穩定的狀態,所以在這些方法中的代碼盡量避免調用其他訪問器
在聲明的次序中 Dealloc 實例變量
▶
應該在與聲明 @interface 同樣的順序中進行 dealloc 實例變量。這樣就使得審查者容易的來驗證。
Setters 復制 NSStrings
▶
Setters 使用一個 NSString ,應始終復制它接受的字符串。
避免拋出異常
▶
不要 @throw Objective-C 異常,但你應該准備從第三方或系統調用中捕獲它們。
nil 檢查
▶
只對邏輯流使用 nil 檢查。
BOOL 陷阱
▶
當將普通的整型值轉換為 BOOL 型時要小心了,應避免將其與 YES 直接比較。
屬性
▶在下列情況下請注意,直接使用@property注解是被允許的:屬性是將會限制你代碼允許在iPhone和Mac OS X 10.5(雪豹)以上版本的Objective-C 2.0的特性。點符號只有聲明@property才允許被訪問。
沒有示例變量的接口
▶接口中除了空大括號之外,請不要聲明任何實例變量。
自動合成實例變量
▶使用自動合成實例變量是被允許的。編寫的代碼必須支持更早之前的編譯工具鏈版本(Xcode 4.3或更早的版本亦或GCC編譯)或者應該直接使用@synthesize注解調用從協議中繼承來的屬性。
自動引用計數(ARC)
▶由於項目使用的是Xcode 4.2或更高版本,並將只運行在64位版Mac OS X 10.7 和 iOS 5.0及更高版本中,ARC 是優先的。手動引用計數在支持早期環境中的歸零弱指針時將不可用。
需要 ARC 的類應該包含一個預處理指令來防止編譯使用手動引用計數。
象 __unsafe _unretained 和 __weak 的所有權限定符應該在變量名的前面。沒必要為變量指定 __strong,因為它是默認的。另一方面,屬性應該始終指定 strong 關鍵字而不是依賴於編譯器的默認值。
被編譯的文件使用 ARC 時需要有預處理指令以防止編譯沒有 ARC。請參見下方的代碼片段以了解詳情。
NSNumber字面值
▶對於利用Xcode4.4或以上版本創建的C語言項目來說,運用NSNumber字面值是被允許的。然而使用這種做法將會限制你代碼對於其他工具鏈的可移植性。
Cocoa模式
委派模式
▶委派對象不應該被保留。
模型、視圖、控制器
▶將模型從視圖中分離。將控制器從視圖和模型中分離。使用@protocols注解回調APIs。
歷史說明
後綴下劃線 vs 前置下劃線
▶後綴下劃線曾經用於表示示例變量的名稱。