簡介: 本文整理自Apple文檔《Coding Guidelines for Cocoa》。這份文檔原意是給Cocoa架構、插件及公共API開發者提供一些編碼指導,實質上相當于Apple内部的編碼規範。在多人協作時,一份統一的代碼規範大大減少開發者之間的溝通成本,極力推薦。 目錄: 一、代碼命名基礎 二、方法 三、函數 四、Property及其他 五、縮寫 一、代碼命名基礎
1.通用原則
1.1 清晰
- 盡量清晰又簡潔,無法兩全時清晰更重要
Code | Commentary |
insertObject:atIndex: | √ |
insert:at: | 不清晰,insert什麼?at表示什麼? |
removeObjectAtIndex: | √ |
removeObject: | √ ,因為參數指明了移除對象 |
remove: | 不清晰,要移除什麼? |
- 通常不應縮寫名稱,即使方法名很長也應完整拼寫
◦ 你可能認為某個縮寫衆所周知,但其實未必,特别是你周圍的開發者語言文化背景不同時
◦ 有一些曆史悠久的縮寫還是可以使用的,詳見第五章
Code | Commentary |
destinationSelection | √ |
destSel | 不清晰 |
setBackgroundColor: | √ |
setBkgdColor: | 不清晰 |
- API命名避免歧義,例如一個方法名有多種了解
Code | Commentary |
sendPort | 發送還是傳回一個port ? |
displayName | 顯示一個名字還是傳回UI界面上的标題? |
1.2 一緻
- 盡力保持Cocoa程式設計接口命名一緻
◦ 如果有疑惑,請浏覽目前頭檔案或者參考文檔
- 當某個類的方法使用了多态時,一緻性尤其重要
◦ 不同類裡,功能相同的方法命名也應相同
Code | Commentary |
- (NSInteger)tag | 定義在 NSView, NSCell, NSControl. |
- (void)setStringValue:(NSString *) | 定義在許多Cocoa類裡 |
1.3 避免自引用(self Reference)
- 命名不應自引用
◦ 這裡的自引用指的是在詞尾引用自身
Code | Commentary |
NSString | √ |
NSStringObject | 自引用,所有NSString都是對象,不用額外聲明 |
- Mask與Notification忽略此規則
Code | Commentary |
NSUnderlineByWordMask | √ |
NSTableViewColumnDidMoveNotification | √ |
2.字首
字首是程式設計接口命名的重要部分,它們區分了軟體的不同功能區域:
- 字首可以防止第三方開發者與Apple的命名沖突
◦ 同樣可以防止Apple内部的命名沖突
- 字首有指定格式
◦ 它由二到三個大寫字母組成,不使用下劃線和子字首
- 命名類、協定、函數、常量和typedef結構體時使用字首
◦ 方法名不使用字首(因為它存在于特定類的命名空間中)
◦ 結構體字段不使用字首
Prefix | Cocoa Framework |
NS | Foundation |
NS | Application Kit |
AB | Address Book |
IB | Interface Builder |
3.書寫約定
在命名API元素時, 使用駝峰命名法(如runTheWordsTogether),并注意以下書寫約定:
- 方法名
◦ 小寫第一個字母,大寫之後所有單詞的首字母,不使用字首
◦ 如果方法名以一個衆所周知的大寫縮略詞開始,該規則不适用
▪ 如TIFFRepresentation (NSImage)
fileExistsAtPath:isDirectory:
- 函數及常量名
◦ 使用與其關聯類相同的字首,并大寫首字母
NSRunAlertPanel
NSCellDisabled
- 标點符号
◦ 由多個單詞組成的名稱,别使用标點符号作為名稱的一部分
▪ 分隔符(下劃線、破折号等)也不能使用
- 避免使用下劃線作為私有方法的字首,Apple保留這一方式的使用
◦ 強行使用可能會導緻命名沖突,即Apple已有的方法被覆寫,這會導緻災難性後果
◦ 執行個體變量使用下劃線作為字首還是允許的
4.class與protocol命名
- class
◦ class的名稱應該包含一個名詞,用以表明這個類是什麼(或者做了什麼),并擁有合适的字首
▪ 如NSString、NSDate、NSScanner、UIApplication、UIButton
- 不關聯class的protocol
◦ 大多數protocol聚集了一堆相關方法,并不關聯class
◦ 這種protocol使用ing形式以和class區分開來
Code | Commentary |
NSLocking | √ |
NSLock | 不好,看起來像是一個class |
- 關聯class的protocol
◦ 一些protoco聚集了一堆無關方法,并試圖與某個class關聯在一起,由這個class來主導
◦ 這種protocol與class同名
▪ 如NSObject protocol
5.頭檔案
頭檔案的命名極其重要,因為它可以指出頭檔案包含的内容:
- 聲明一個孤立的class或protocol
◦ 将聲明放入單獨的檔案
◦ 使頭檔案名與聲明的class/protocol相同
Header file | Declares |
NSLocale.h | 包含NSLocale class. |
- 聲明關聯的class或protocol
◦ 将關聯的聲明(class/category/protocol)放入同一個頭檔案
◦ 頭檔案名與主要的class/category/protocol相同
Header file | Declares |
NSString.h | 包含NSString和NSMutableString classes. |
NSLock.h | 包含NSLocking protocol 和 NSLock, NSConditionLock, NSRecursiveLock classes. |
- Framework頭檔案
◦ 每個framework都應該有一個同名頭檔案
◦ Include了架構内其他所有頭檔案
Header file | Framework |
Foundation.h | Foundation.framework. |
- 添加API到另一個framework
◦ 如果要在一個framework中為另一個framework的class catetgory添加方法,加上單詞“Additions”
▪ 如Application Kit的NSBundleAdditions.h 檔案
- 關聯的函數、資料類型
◦ 如果你有一組關聯的函數、常量、結構體或其他資料類型,将它們放到一個名字合适的頭檔案中
▪ 如Application Kit的NSGraphics.h
二、方法
1.通用原則
- 以小寫字母開始,之後單詞的首字母大寫
◦ 以衆所周知的縮寫開始可以大寫,如TIFF、PDF
◦ 私有方法可以加字首
- 如果方法代表對象接收的動作,以動詞開始
◦ 不要使用 do 或 does 作為名字的一部分,因為助動詞在這裡很少有實際意義
◦ 同樣的,也别在動詞之前使用副詞和形容詞
- (void)invokeWithTarget:(id)target;
- (void)selectTabViewItem:(NSTabViewItem *)tabViewItem
- 如果方法傳回接收者的屬性,以 接收者 + 接收的屬性 命名
◦ 除非間接傳回多個值,否則不要使用 get 單詞(為了與accessor methods區分)
- (NSSize)cellSize; | √ |
- (NSSize)calcCellSize; | ✗ |
- (NSSize)getCellSize; | ✗ |
- 在所有參數之前使用關鍵字
- (void)sendAction:(SEL)aSelector toObject:(id)anObject forAllCells:(BOOL)flag; | √ |
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag; | ✗ |
- 確定參數之前的關鍵字充分描述了參數
- (id)viewWithTag:(NSInteger)aTag; | √ |
- (id)taggedView:(int)aTag; | ✗ |
- 建立自定義 init 方法時,記得指明關聯的元素
- (id)initWithFrame:(CGRect)frameRect; | √ |
- (id)initWithFrame:(NSRect)frameRect mode:(int)aMode cellClass:(Class)factoryId numberOfRows:(int)rowsHigh numberOfColumns:(int)colsWide; | √ |
- 不要使用 and 來連接配接作為接收者屬性的關鍵字
◦ 雖然下面的例子使用 and 看似不錯,但是一旦參數非常多時就容易出現問題
- (int)runModalForDirectory:(NSString *)path file:(NSString *)name types:(NSArray *)fileTypes; | √ |
- (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes; | ✗ |
- 除非方法描述了兩個獨立的操作,才使用 and 來連接配接它們
- (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag; | √ |
2.getter和setter方法(Accessor Methods)
- 如果property表示為名詞,格式如下
◦ - (type)noun;
◦ - (void)setNoun:(type)aNoun;
◦ - (BOOL)isAdjective;
- (NSString *)title;
- (void)setTitle:(NSString *)aTitle;
- 如果property表示為形容詞,格式如下
◦ - (BOOL)isAdjective;
◦ - (void)setAdjective:(BOOL)flag;
- (BOOL)isEditable;
- (void)setEditable:(BOOL)flag;
- 如果property表示為動詞,格式如下(動詞用一般現在時)
◦ - (BOOL)verbObject;
◦ - (void)setVerbObject:(BOOL)flag;
- (BOOL)showsAlpha;
- (void)setShowsAlpha:(BOOL)flag;
- 不要把動詞的過去分詞形式當作形容詞使用
- (void)setAcceptsGlyphInfo:(BOOL)flag; | √ |
- (BOOL)acceptsGlyphInfo; | √ |
- (void)setGlyphInfoAccepted:(BOOL)flag; | ✗ |
- (BOOL)glyphInfoAccepted; | ✗ |
- 你可能使用情态動詞(can、should、will等)來增加可讀性,不過不要使用 do或 does
- (void)setCanHide:(BOOL)flag; | √ |
- (BOOL)canHide; | √ |
- (void)setShouldCloseDocument:(BOOL)flag; | √ |
- (BOOL)shouldCloseDocument; | √ |
- (void)setDoesAcceptGlyphInfo:(BOOL)flag; | ✗ |
- (BOOL)doesAcceptGlyphInfo; | ✗ |
- 隻有方法需要間接傳回多個值的情況下才使用 get
◦ 像這種接收多個參數的方法應該能夠傳入nil,因為調用者未必對每個參數都感興趣
- (void)getLineDash:(float *)pattern count:(int *)count phase:(float *)phase; | NSBezierPath. |
3.Delegate方法
- 以發送消息的對象開始
◦ 省略了字首的類名和首字母小寫
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;
- 以發送消息的對象開始的規則不适用下列兩種情況
◦ 隻有一個sender參數的方法
- (BOOL)applicationOpenUntitledFile:(NSApplication *)sender;
◦ 響應notification的方法(方法的唯一參數就是notification)
- (void)windowDidChangeScreen:(NSNotification *)notification;
- 使用單詞 did 和 will 來通知delegate
◦ did 表示某些事已發生
◦ will 表示某些事将要發生
- (void)browserDidScroll:(NSBrowser *)sender;
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window;
- 詢問delegate是否可以執行某個行為時可以使用 did 或 will,不過 should 更完美
- (BOOL)windowShouldClose:(id)sender;
4.集合方法
- 為了管理集合中的元素,集合應該有這幾個方法
◦ - (void)addElement:(elementType)anObj;
◦ - (void)removeElement:(elementType)anObj;
◦ - (NSArray *)elements;
- (void)addLayoutManager:(NSLayoutManager *)obj;
- (void)removeLayoutManager:(NSLayoutManager *)obj;
- (NSArray *)layoutManagers;
- 如果集合是無序的,傳回一個NSSet比NSarray更好
- 如果需要在集合中的特定位置插入元素,使用類似下面的方法
- (void)insertLayoutManager:(NSLayoutManager *)obj atIndex:(int)index; - (void)removeLayoutManagerAtIndex:(int)index;
- 其他集合方法示例
- (void)addChildWindow:(NSWindow *)childWin ordered:(NSWindowOrderingMode)place; - (void)removeChildWindow:(NSWindow *)childWin; - (NSArray *)childWindows; - (NSWindow *)parentWindow; - (void)setParentWindow:(NSWindow *)window;
5.方法參數
- 參數名以小寫字母開始,之後的單詞首字母大寫
如:removeObject:(id)anObject
- 别使用 ”pointer” 或 ”ptr” 命名
◦ 參數類型裡就已表明它是否是一個指針
- 避免隻有一到二個字母的參數名
- 避免隻有幾個字母的縮寫
...action:(SEL)aSelector ...alignment:(int)mode ...atIndex:(int)index ...content:(NSRect)aRect ...doubleValue:(double)aDouble ...floatValue:(float)aFloat ...font:(NSFont *)fontObj ...frame:(NSRect)frameRect ...intValue:(int)anInt ...keyEquivalent:(NSString *)charCode ...length:(int)numBytes ...point:(NSPoint)aPoint ...stringValue:(NSString *)aString ...tag:(int)anInt ...target:(id)anObject ...title:(NSString *)aString
6.私有方法
- 不要使用下劃線作為私有方法的字首,Apple保留這一使用方式
◦ 因為若是你的私有方法名已被Apple使用,覆寫它将會産生極難追蹤的BUG
- 如果繼承自大型Cocoa架構(如UIView),請確定子類的私有方法名與父類不一樣
◦ 可以為私有方法加一個字首,如公司名或項目名:XX_
▪ 例如你的項目叫做Byte Flogger,那麼字首可能是:BF_addObject
◦ 總之,為子類的私有方法添加字首是為了不覆寫其父類的私有方法
三、函數
- 函數的命名類似方法,但有兩點要注意
◦ 你使用的類和常量擁有相同的字首
◦ 字首後的首字母大寫
- 許多函數名以描述其作用的動詞開始
NSHighlightRect NSDeallocateObject
- 查詢屬性的函數有進一步的命名規則
◦ 如果函數傳回首個參數的屬性,省略動詞
unsigned int NSEventMaskFromType(NSEventType type)
float NSHeight(NSRect aRect)
◦ 如果通過reference傳回了值,使用 “Get”
const char *NSGetSizeAndAlignment(const char *typePtr, unsigned int *sizep, unsigned int *alignp)
◦ 如果傳回的是boolean值,應該靈活使用動詞
BOOL NSDecimalIsNotANumber(const NSDecimal *decimal)
四、Property及其他
1.Property與執行個體變量
1.1 Property
- Property命名規則與第二章accessor methods一樣(因為兩者緊密聯系)
- 如果property表示為一個名詞或動詞,格式如下
◦ @property (…) 類型 名詞/動詞 ;
@property (strong) NSString *title;
@property (assign) BOOL showsAlpha;
- 如果property表示為一個形容詞
◦ 可省略 ”is” 字首
◦ 但要指定getter方法的慣用名稱
@property (assign, getter=isEditable) BOOL editable;
1.2 執行個體變量
- 通常不應該直接通路執行個體變量
◦ init、dealloc、accessor methods等方法内部例外
- 執行個體變量以下劃線 “_” 開始
◦ 確定執行個體變量描述了所存儲的屬性
@implementation MyClass {
BOOL _showsTitle;
}
- 如果想要修改property的執行個體變量名,使用 @synthesize語句
@implementation MyClass @synthesize showsTitle=_showsTitle;
為一個class添加執行個體變量時,有幾點需要注意:
- 避免聲明公有執行個體變量
◦ 開發者關注的應該是對象接口,而不是其資料細節
◦ 你可以通過使用property來避免聲明執行個體變量
- 如果需要聲明執行個體變量,指定關鍵字@private 或 @protected
◦ 如果你希望子類可以直接通路某個執行個體變量,使用 @protected 關鍵字
- 如果一個執行個體變量是某個類可通路的屬性,確定寫了accessor methods
◦ 如果有可能,還是使用property
2.常量
2.1 枚舉常量
- 使用枚舉來關聯一組integer常量
- 枚舉常量和typedef遵循函數的命名規範,下面的例子是 NSMatrix.h
typedef enum _NSMatrixMode { NSRadioModeMatrix = 0, NSHighlightModeMatrix = 1, NSListModeMatrix = 2, NSTrackModeMatrix = 3 } NSMatrixMode;
- 你可以為bit masks之類的東西建立一個匿名枚舉
enum { NSBorderlessWindowMask = 0, NSTitledWindowMask = 1 << 0, NSClosableWindowMask = 1 << 1, NSMiniaturizableWindowMask = 1 << 2, NSResizableWindowMask = 1 << 3 };
2.2 使用const關鍵字的常量
- 使用const關鍵字來建立一個float常量
◦ 你可以使用const關鍵字來建立一個與其他常量不相關的integer常量,否則,使用枚舉
◦ 使用const關鍵字的常量也遵循函數的命名規則
const float NSLightGray;
2.3 其他常量類型
- 通常不應使用 #define 預編譯指令來建立常量
◦ integer常量,使用枚舉
◦ float常量,使用 const 修飾符
- 對 #define 預編譯指令,大寫所有字母
◦ 比如 DEBUG 判斷
#ifdef DEBUG
- 注意宏指令的字首和字尾都有雙下劃線
__MACH__
- 定義NSString常量來作為Notification和Key值
◦ 這樣做可以有效防止拼寫錯誤
APPKIT_EXTERN NSString *NSPrintCopies;
3.Notifications與Exceptions
3.1 Notifications
- Notification的格式
[Name of associated class] + [Did | Will] + [UniquePartOfName] + Notification
NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
NSTextViewDidChangeSelectionNotification
NSColorPanelColorDidChangeNotification
3.2 Exceptions
- Exception的格式
[Prefix] + [UniquePartOfName] + Exception
NSColorListIOException
NSColorListNotEditableException
NSDraggingException
NSFontUnavailableException
NSIllegalSelectorException
五、縮寫
- 設計程式設計接口時通常不應使用縮寫,但下列已被廣泛使用的縮寫名稱除外
◦ 标準C庫中的縮寫名,如:alloc、init
◦ 參數名可自由使用縮寫,如:imageRep、col、obj、otherWin
縮寫 | 全稱 |
alloc | Allocate. |
alt | Alternate. |
app | Application. |
calc | Calculate. |
dealloc | Deallocate. |
func | Function. |
horiz | Horizontal. |
info | Information. |
init | Initialize. |
int | Integer |
max | Maximum. |
min | Minimum. |
msg | Message. |
nib | Interface Builder archive. |
pboard | Pasteboard. |
rect | Rectangle. |
Rep | Representation. |
temp | Temporary. |
vert | Vertical. |
縮寫 | 全稱 |
ASCII | American Standard Code for Information Interchange |
Portable Document Format | |
XML | Extensible Markup Language |
HTML | HyperText Markup Language |
URL | Uniform Resource Locator |
RTF | Rich Text Format |
HTTP | HyperText Transfer Protocol |
TIFF | Tagged Image File Format |
JPG/JPEG | Joint Photographic Experts GROUP |
PNG | Portable Network Graphic Format |
GIF | Graphics Interchange Format |
LZW | Lempel Ziv Welch |
ROM | Read-Only Memory |
RGB | R(red)、G(green)、B(blue) |
CMYK | C:Cyan、M:Magenta、Y:Yellow、K:Key Plate(blacK) |
MIDI | Musical Instrument Digital Interface |
FTP | File Transfer Protocol |
本文轉載自:http://www.cnblogs.com/yangfaxian/p/4673894.html?sukey=a805c0b270074a06b8513acfc04338fb98e18e6592e6455019254895dbfd0bba457fb535e3d3314c00bae1b10f6409db