注意事項
顯示在本指南中的隱藏細節
這個風格指南包含很多最初不可見的細節。它們被標記為三角形表徵圖,你可以在左邊看到。現在點擊它,你應該會看到“萬歲”出現在下面。
背景
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++)編碼指南和實踐的。這些指南的很多地方已經進化並在其他項目和團隊已經過時。Google開發的開源項目符合本指南中的要求。
Google已經發布了符合這些準則的,作為Mac項目的Google工具箱(以下簡稱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 前置底線
▶尾碼底線曾經用於表示樣本變數的名稱。