[iOS譯文]Cocoa編碼規范

mf7x 9年前發布 | 17K 次閱讀 Cocoa iOS開發 移動開發

原文  http://www.cnblogs.com/yangfaxian/p/4673894.html

 

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

PDF

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

 本文由用戶 mf7x 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!