Cocoa编码规范
介紹Cocoa編碼規(guī)范
開(kāi)發(fā)一個(gè)Cocoa framework,插件或者其他具有公開(kāi)API的可執(zhí)行文件時(shí),需要采取與那些應(yīng)用開(kāi)發(fā)不同的方法和約定。你產(chǎn)品的初始客戶端是開(kāi)發(fā)者,非常重要的一點(diǎn)就是不要讓他們?yōu)槟愕木幊探涌诟械嚼Щ蟆R韵卤闶茿PI的命名約定,能夠幫助你讓你的接口保持一致和清晰,這些對(duì)于你來(lái)說(shuō),遲早排得上用場(chǎng)。同樣還有比較特殊的針對(duì)更重要的與框架有關(guān)的編程技術(shù),例如,版本標(biāo)注、二進(jìn)制兼容性、錯(cuò)誤處理和內(nèi)存管理。此篇文章同樣包含Cocoa命名約定和推薦的框架編程實(shí)踐。
本文主要有兩部分。編程接口的命名規(guī)范以及關(guān)于框架編程方面的討論。
接口的命名規(guī)范
代碼命名基礎(chǔ)
對(duì)于面向?qū)ο筌浖?kù)的設(shè)計(jì),經(jīng)常忽視的一點(diǎn)是類、方法、函數(shù)、常量以及其它編程接口元素的命名。本部分將會(huì)討論對(duì)于大多數(shù)的Cocoa接口的一些通用的命名約定。
總則
簡(jiǎn)潔
-
盡可能簡(jiǎn)單明了,但是過(guò)于簡(jiǎn)單會(huì)讓人看不懂:
代碼評(píng)注 insetObject:atIndex 不錯(cuò) insert:at: 不明了; 插入了什么? “at”表示什么意思? removeObjectAtIndex: 不錯(cuò) removeObject: 不錯(cuò),因?yàn)檫@個(gè)方法表明了移除這個(gè)參數(shù)對(duì)象 remove: 不明了; 移除什么? -
一般來(lái)說(shuō),不要使用縮寫(xiě)。使用全拼,即使單詞比較長(zhǎng)
代碼評(píng)注 destinationSelection 不錯(cuò) destSel 不明了 setBackgroundColor: 不錯(cuò) setBkgdColor: 不明了
你可能認(rèn)為有些縮寫(xiě)必要有名,其實(shí)非你所料,尤其是當(dāng)你的方法或者函數(shù)名遇到一個(gè)不同文化和語(yǔ)言的開(kāi)發(fā)者時(shí)。比如在國(guó)內(nèi)BAT,大家都知道說(shuō)的是百度、阿里、騰訊,但是外國(guó)人卻不知道說(shuō)的是什么。
-
然而,少數(shù)縮寫(xiě)詞確實(shí)常見(jiàn),而且有很長(zhǎng)的使用歷史。你可以繼續(xù)使用它們;可以參見(jiàn)后文的可接受的縮略詞和首字母縮略詞。
-
避免模棱兩可的API命名,例如具有多種解釋的方法名。
代碼評(píng)注 sendPort 是要發(fā)送還是需要返回端口? displayName 是需要顯示一個(gè)名字還是需要返回一個(gè)UI的標(biāo)題?
一致性
-
在整個(gè)Cocoa編程接口中的命名保持一致性。如果你不太確定,請(qǐng)查看當(dāng)前的頭文件或者引用文檔。
-
當(dāng)你一個(gè)類的方法需要利用到多態(tài),這種情況下一致顯得尤為重要。方法需要在不同的類中具有相同的作用,并且需要有相同的名字。
代碼評(píng)注 - (NSInteger)tag 在UIView, UIControl中定義 - (void)setStringValue:(NSString *) 在許多Cocoa類中定義
無(wú)自引用
指不能在當(dāng)前命名中附帶本身的屬性,比如一個(gè)人叫張三,我們不要把他叫做張三人、人張三。
-
名字不能自引用
代碼評(píng)注 NSString 沒(méi)問(wèn)題 NSStringObject 自引用
代碼評(píng)注 NSUnderlineByWordMask 沒(méi)問(wèn)題 NSTableViewColumnDidMoveNotification 沒(méi)問(wèn)題
前綴
在編程接口命名中,前綴是一個(gè)重要部分。這個(gè)是用來(lái)區(qū)分軟件不同的功能范圍。這樣的不同的范圍,通常是一個(gè)框架中的包或者(例如基礎(chǔ)框架和應(yīng)用包)相關(guān)的框架。前綴能夠防止第三方開(kāi)發(fā)者定義的內(nèi)容與Apple定義的內(nèi)容相沖突。
-
前綴有規(guī)定的格式。它包含2-3個(gè)大寫(xiě)字母,并且不會(huì)使用下劃線分割或者“子前綴”。下面有些例子:
前綴Cocoa框架 NS Foundation UI UIKit AB Address Book IB Interface Builder -
在類、協(xié)議、函數(shù)、常量和定義結(jié)構(gòu)體命名的時(shí)候,請(qǐng)使用前綴。不要在方法命名的時(shí)候使用前綴;方法是有通過(guò)類來(lái)定義的命名空間。同樣,不要在結(jié)構(gòu)體內(nèi)的字段上使用前綴。
排版約定
在API元素命名的時(shí)候,請(qǐng)遵循一些簡(jiǎn)單的排版約定:
-
對(duì)于由多個(gè)單詞組成的命名,不要使用標(biāo)點(diǎn)符號(hào)作為名字的一部分,或者作為分隔符(下劃線、破折號(hào)等);而且每個(gè)單詞的首字母要大寫(xiě),并且連在一起(例如,runTheWordsTogether)——這個(gè)被稱為駝峰式命名法。然而,要注意以下限制:
- 對(duì)于方法名稱,首字母小寫(xiě),并將其他單詞的首字母大寫(xiě)。不要使用前綴。例如:fileExistsAtPath:isDirectory:。對(duì)于方法的命名有一個(gè)例外的地方就是以一個(gè)有名的首字母縮寫(xiě)詞打頭,例如NSImage的TIFFRepresentation方法。
- 對(duì)于函數(shù)和常量的命名,對(duì)于相關(guān)的類使用相同的前綴,并且緊接著后面的一個(gè)單詞首字母大寫(xiě)。例如:NSRunAlertPanel、NSCellDisabled。
- 避免使用下劃線字符作為私有方法的命名前綴(對(duì)于使用下劃線字符作為實(shí)例變量的命名前綴是允許的)。Apple保留這種約定的使用權(quán)。如果第三方使用,可能會(huì)導(dǎo)致命名空間的沖突;可能會(huì)在毫不知情的情況下覆蓋了其中一個(gè)已經(jīng)存在的私有方法,從而帶來(lái)災(zāi)難性的后果。參見(jiàn)私有方法部分來(lái)獲取對(duì)于私有API方法命名的約定建議。
類和協(xié)議的命名
類的命名中應(yīng)當(dāng)包含一個(gè)能夠清楚的表明這個(gè)類(或者類的對(duì)象)是什么,或者是做什么的名詞。這個(gè)名字需要有一個(gè)適當(dāng)?shù)那熬Y。Foundation框架和應(yīng)用框架里面到處都是例子;例如: NSString, NSDate, NSScanner, NSApplication, UIApplication, NSButton, 以及UIButton。
協(xié)議應(yīng)該依據(jù)組作用來(lái)命名:
一般情況下,大多數(shù)協(xié)議組相關(guān)的方法與任何類都不相關(guān)。這種類型的協(xié)議應(yīng)該在命名上與類區(qū)分開(kāi)來(lái)。一個(gè)常見(jiàn)的約定就是使用動(dòng)名詞(“…ing”)格式。例如:
| NSLocking | 不錯(cuò) |
| NSLock | 不是很好 (看起來(lái)像一個(gè)類的命名) |
-
一些協(xié)議中包含多個(gè)不相關(guān)的方法(而不是創(chuàng)建多個(gè)單獨(dú)的小的協(xié)議)。這些協(xié)議與類相關(guān),這是協(xié)議最重要的表達(dá)方式。在這種情況下,我們約定,保持協(xié)議和類名相同的方式。
這種協(xié)議的例子就是NSObject協(xié)議。可以使用這個(gè)協(xié)議中的方法來(lái)查詢?nèi)我忸悓蛹?jí)的對(duì)象的位置,可以調(diào)用指定方法,增加或減少它的引用數(shù)。因?yàn)轭怤SObject提供了這些方法的初始表達(dá)式,協(xié)議的命名在類名之后。
頭文件
你如何命名頭文件非常重要,因?yàn)榧s定中,你用它來(lái)顯示這個(gè)文件包含的內(nèi)容:
-
聲明一個(gè)單獨(dú)的類或協(xié)議。如果一個(gè)類或協(xié)議不屬于一個(gè)組的一部分,將它的聲明放在一個(gè)單獨(dú)的文件中,這個(gè)文件的名字是已經(jīng)聲明過(guò)的類或者協(xié)議。
頭文件聲明 NSLocale.h NSLocale類 -
聲明相關(guān)的類和協(xié)議。對(duì)于一個(gè)含有相關(guān)聲明的組(類、分類和協(xié)議),將聲明放在一個(gè)與初始類、分類或協(xié)議命名相關(guān)的文件中。
頭文件聲明 NSString.h NSString和NSMutableString類 NSLock.h NSLocking協(xié)議和NSLock, NSConditionLock, 以及 NSRecursiveLock 類 -
包含框架頭文件。每一個(gè)框架應(yīng)當(dāng)有一個(gè)頭文件,在框架后面命名,這個(gè)頭文件應(yīng)當(dāng)包含所有的框架的公共頭文件。
頭文件聲明 Foundation.h Foundation.framework -
在其它框架中添加API到一個(gè)類中。如果你想要在一個(gè)框架中中聲明一個(gè)在其它框架中類的分類中的方法,請(qǐng)?jiān)谠碱惖拿竺孀芳印癆dditions”;一個(gè)典型的例子就是應(yīng)用包中的NSBundleAdditions.h 頭文件。
-
相關(guān)的函數(shù)和數(shù)據(jù)類型。如果你有一組相關(guān)的函數(shù)、常量、結(jié)構(gòu)體以及其它數(shù)據(jù)類型,可以將他們放在一個(gè)恰當(dāng)命名的頭文件中,例如 NSGraphics.h(應(yīng)用包)。
方法命名
方法或許是你編程接口中最常見(jiàn)的元素,因此在它們的命名方面應(yīng)當(dāng)特別小心。
一般規(guī)則
-
方法名應(yīng)該以小寫(xiě)字母打頭,然后緊接著后面每一個(gè)單詞的首字母大寫(xiě)。不要使用前綴。可以參見(jiàn)前面的排滿約定。
對(duì)于以上指南,有兩個(gè)特別的例外,你可能用一個(gè)很有名的大寫(xiě)縮寫(xiě)詞為方法名打頭(例如 TIFF或PDF),而且你可能會(huì)使用前綴來(lái)標(biāo)記組以及私有方法(參見(jiàn)上面的私有方法)。
-
當(dāng)一個(gè)方法表示一個(gè)對(duì)象執(zhí)行的動(dòng)作的話,請(qǐng)以一個(gè)動(dòng)詞打頭:
- (void)invokeWithTarget:(id)target; - (void)selectTabViewItem:(NSTabViewItem *)tabViewItem不要使用“do”或者“does”作為方法名的一部分,因?yàn)檫@些輔助的動(dòng)詞很少能夠增強(qiáng)意思。同樣,絕不要在動(dòng)詞前面使用副詞或者形容詞。
-
如果一個(gè)方法返回給調(diào)用者一個(gè)屬性的話,用這個(gè)屬性命名方法。沒(méi)有必要使用“get”。除非不是直接返回一個(gè)或多個(gè)返回值。
方法命名評(píng)述 - (NSSize)cellSize 正確 - (NSSize)calcCellSize 錯(cuò)誤 - (NSSize)getCellSize 錯(cuò)誤 -
在所有參數(shù)前面使用關(guān)鍵詞
方法命名評(píng)述 - (void)sendAction:(SEL)aSelector toObject:(id)anObject forAllCells:(BOOL)flag 正確 - (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag 錯(cuò)誤 -
在參數(shù)之前描述這個(gè)參數(shù)
方法命名評(píng)述 - (id)viewWithTag:(NSInteger)aTag 正確 - (id)taggedView:(int)aTag 錯(cuò)誤 -
當(dāng)你想要?jiǎng)?chuàng)建一個(gè)比繼承的方法更加明確的方法的時(shí)候,請(qǐng)?jiān)诜椒ńY(jié)束之后,添加一些關(guān)鍵詞。
方法命名評(píng)述 - (id)initWithFrame:(CGRect)frameRect NSView,UIView - (id)initWithFrame:(NSRect)frameRect mode:(int)aMode cellClass:(Class)factoryId numberOfRows:(int)rowsHigh numberOfColumns:(int)colsWide NSMatrix, NSView的子類 -
不要在描述屬性的關(guān)鍵詞上使用“and”。
方法命名評(píng)述 - (int)runModalForDirectory:(NSString )path file:(NSString ) name types:(NSArray *)fileTypes 正確 - (int)runModalForDirectory:(NSString )path andFile:(NSString )name andTypes:(NSArray *)fileTypes 錯(cuò)誤
盡管在這個(gè)例子中,采用“and”看起來(lái)還可以,但是當(dāng)你創(chuàng)建越來(lái)越多關(guān)鍵詞方法的時(shí)候,會(huì)出問(wèn)題。
-
如果一個(gè)方法描述了兩個(gè)單獨(dú)的動(dòng)作,可以使用“and”來(lái)連接他們。
方法命名評(píng)述 - (BOOL)openFile:(NSString )fullPath withApplication:(NSString )appName andDeactivate:(BOOL)flag NSWorkspace
存取方法
存取方法是用來(lái)設(shè)置和返回一個(gè)對(duì)象的屬性值。有推薦的格式,取決于這個(gè)屬性表達(dá)方式:
-
如果這個(gè)屬性是名詞的話,格式是這樣的:
- (type)noun; - (void)setNoun:(type)aNoun;舉個(gè)例子:
- (NSString *)title; - (void)setTitle:(NSString *)aTitle; -
如果這個(gè)屬性是形容詞,格式是這樣的:
- (BOOL)isAdjective; - (void)setIsAdjective:(BOOL)flag;舉個(gè)例子:
- (BOOL)isEditable; - (void)setEditable:(BOOL)flag; -
如果這個(gè)屬性是一個(gè)動(dòng)詞,格式是這樣的:
- (BOOL)verbObject; - (void)setVerbObject:(BOOL)flag;舉個(gè)例子:
- (BOOL)showsAlpha; - (void)setShowsAlpha:(BOOL)flag;動(dòng)詞應(yīng)當(dāng)使用簡(jiǎn)單的現(xiàn)在時(shí)。
-
不要通過(guò)分詞形式將動(dòng)詞轉(zhuǎn)換成形容詞:
方法命名評(píng)述 - (void)setAcceptsGlyphInfo:(BOOL)flag 正確 - (BOOL)acceptsGlyphInfo 正確 - (void)setGlyphInfoAccepted:(BOOL)flag 錯(cuò)誤 - (BOOL)glyphInfoAccepted 錯(cuò)誤 -
你可能會(huì)使用情態(tài)動(dòng)詞來(lái)闡述意思,但是不用使用“do” 或“does”。
方法命名評(píng)述 - (void)setCanHide:(BOOL)flag 正確 - (BOOL)canHide 正確 - (void)setShouldCloseDocument:(BOOL)flag 正確 - (BOOL)shouldCloseDocument 正確 - (void)setDoesAcceptGlyphInfo:(BOOL)flag 錯(cuò)誤 - (BOOL)doesAcceptGlyphInfo 錯(cuò)誤 -
僅當(dāng)方法間接返回對(duì)象和值的時(shí)候,使用“get”命名。而且僅當(dāng)多個(gè)條目需要返回的時(shí)候。
方法命名評(píng)述 - (void)getLineDash:(float *)pattern count:(int *)count phase:(float *)phase NSBezierPath 在以上這些方法中,方法的實(shí)現(xiàn)應(yīng)當(dāng)考慮針對(duì)這些輸入輸出參數(shù)可接受NULL值,來(lái)指明調(diào)用者不必對(duì)一個(gè)或者多個(gè)返回值感興趣。
代理方法
代理方法是指在某一事件發(fā)生的時(shí)候,一個(gè)對(duì)象調(diào)用它的代理(如果實(shí)現(xiàn)了這個(gè)代理)。它們有獨(dú)特的格式,同樣適用于對(duì)象數(shù)據(jù)源的方法調(diào)用。
-
方法打頭請(qǐng)標(biāo)明是哪個(gè)類的對(duì)象發(fā)送信息的:
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row; - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;類名省略前綴,并且第一個(gè)字母小寫(xiě)。
-
一個(gè)冒號(hào)后附帶類名(參數(shù)是代理對(duì)象的實(shí)例),除非這個(gè)方法只有一個(gè)參數(shù),發(fā)送者。
- (BOOL)applicationOpenUntitledFile:(NSApplication *)sender; -
有一個(gè)例外就是,方法作為通知被發(fā)送的結(jié)果來(lái)調(diào)用。這種情況下,這個(gè)單獨(dú)的參數(shù)就是通知對(duì)象。
- (void)windowDidChangeScreen:(NSNotification *)notification; -
在方法名上使用“did” 或 “will”用來(lái)通知代理,有事情已經(jīng)發(fā)生或者即將發(fā)生。
- (void)browserDidScroll:(NSBrowser *)sender; - (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window; -
盡管你可以在方法名上使用“did” 或“will”,在方法被調(diào)用的時(shí)候,請(qǐng)求代理為另外一個(gè)對(duì)象做些事情,還是推薦“should”。
- (BOOL)windowShouldClose:(id)sender;
集合類的方法
對(duì)于那些管理對(duì)象集合的對(duì)象(每一個(gè)被稱為集合的元素),約定為以下方法格式:
- (void)addElement:(elementType)anObj; - (void)removeElement:(elementType)anObj; - (NSArray *)elements;例如:
- (void)addLayoutManager:(NSLayoutManager *)obj; - (void)removeLayoutManager:(NSLayoutManager *)obj; - (NSArray *)layoutManagers;以下是對(duì)這個(gè)指南的限制和改進(jìn):
- 如果這個(gè)集合的確是無(wú)序的,返回一個(gè)NSSet對(duì)象,而不是一個(gè)NSArray對(duì)象。
- 如果向一個(gè)集合中指定位置插入一個(gè)元素非常重要,采用以下形式的方法:- (void)insertLayoutManager:(NSLayoutManager *)obj atIndex:(int)index; - (void)removeLayoutManagerAtIndex:(int)index;
還有一些針對(duì)于MRC的說(shuō)明,這里就不列舉了。在非ARC下,確定好需要強(qiáng)弱引用。如果是強(qiáng)引用,使用NSArray、NSDictionary, NSSet等;如果是弱引用,則使用NSPointerArray、NSMapTable、NSHashTable。
方法參數(shù)
這里有一些設(shè)計(jì)方法參數(shù)命名的一般規(guī)則:
- 和方法一樣,參數(shù)要以一個(gè)小寫(xiě)字母打頭,并且后續(xù)每一個(gè)單詞的首字母要大寫(xiě)(例如: removeObject:(id)anObject)。
- 不要在參數(shù)名中使用“pointer” 或“ptr”。讓參數(shù)的類型而不是它的名稱,聲明它是否是指針。
- 避免1-2個(gè)字母的參數(shù)名字。
- 避免縮寫(xiě)
一般來(lái)說(shuō)(在Cocoa中),以下關(guān)鍵詞和參數(shù)會(huì)同時(shí)使用:
...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 ...length:(int)numBytes ...point:(NSPoint)aPoint ...stringValue:(NSString *)aString ...tag:(int)anInt ...target:(id)anObject ...title:(NSString *)aString私有方法
在大多數(shù)情況下,私有方法名稱通常遵循與公共方法名稱相同的規(guī)則。然而,一個(gè)常見(jiàn)的約定就是給私有方法一個(gè)前綴,以便它很容易與公共方法進(jìn)行區(qū)分。即使采用這種約定,私有方法的名稱也可能導(dǎo)致一種特殊類型的問(wèn)題。當(dāng)您設(shè)計(jì)Cocoa框架類的子類時(shí),您無(wú)法知道您的私有方法是否無(wú)意中覆蓋了具有相同名稱的私有框架方法。
大多數(shù)Cocoa框架中的私有方法有一個(gè)下劃線前綴(例如:_fooData ),用來(lái)標(biāo)記它是私有方法。基于這個(gè)事實(shí),有以下兩個(gè)建議:
- 不要使用下劃線字符作為私有方法的前綴。Apple保留了這一慣例。
- 如果是一個(gè)大型Cocoa框架類(如NSView或UIView)的子類,你想要絕對(duì)確定你的私有方法的名稱與超類中的名稱不同,你可以在你的私有方法前面加上一個(gè)你自己的前綴。這個(gè)前綴盡可能的唯一,或許基于你的公司或者項(xiàng)目,諸如XX_格式。所以,若你的項(xiàng)目叫做Byte Flogger,那么這個(gè)方法名可以是BF_addObject: 。
盡管給私有方法加上前綴的命名方式看起來(lái)像是與先前的提出的方法以類為區(qū)分的命名空間存在矛盾之處,但是這里的意圖在于:防止無(wú)意識(shí)的重寫(xiě)了父類的私有方法。
函數(shù)命名
Objective-C 允許你通過(guò)函數(shù)來(lái)實(shí)現(xiàn)和方法一樣的功能。當(dāng)潛在的對(duì)象總是一個(gè)單例或者當(dāng)你要處理明顯的功能性的子系統(tǒng),你可以使用函數(shù),而不是類中的方法。
函數(shù)有一些通用的命名規(guī)則,您應(yīng)該遵循:
-
函數(shù)的命名格式有點(diǎn)類似方法的命名,但是有一些例外:
- 函數(shù)名以你使用的類或者常量前綴開(kāi)始。
- 前綴后面的第一個(gè)單詞首字母大寫(xiě)。
-
大多數(shù)的函數(shù)名以動(dòng)詞打頭,用來(lái)表示這個(gè)函數(shù)的作用:
NSHighlightRect NSDeallocateObject
如果這個(gè)函數(shù)是用來(lái)查詢屬性的話,還有一套其它的規(guī)則:
- 如果你的函數(shù)返回的是第一個(gè)參數(shù)的屬性,請(qǐng)忽略掉動(dòng)詞。unsigned int NSEventMaskFromType(NSEventType type) float NSHeight(NSRect aRect)
- 如果返回的是引用類型,請(qǐng)使用“Get”。const char *NSGetSizeAndAlignment(const char *typePtr, unsigned int *sizep, unsigned int *alignp)
- 如果返回的是布爾類型,函數(shù)應(yīng)該以一個(gè)變化動(dòng)詞打頭。BOOL NSDecimalIsNotANumber(const NSDecimal *decimal)
屬性和數(shù)據(jù)類型命名
這個(gè)部分介紹了聲明的屬性,實(shí)例變量,常量,通知和異常的命名約定。
聲明的屬性和實(shí)例變量
屬性的聲明實(shí)際上是聲明屬性的讀寫(xiě)方法,所以聲明屬性的命名約定大體上和存取方法的命名約定相同(參見(jiàn)存取方法)。
-
如果屬性是一個(gè)名詞或者動(dòng)詞,格式是:
@property (…) type nounOrVerb;例如:
@property (strong) NSString *title; @property (assign) BOOL showsAlpha; -
如果聲明屬性是一個(gè)形容詞,然而需要注意的是,屬性名忽略掉“is”前綴,但是指定約定的get讀取方法名,例如:
@property (assign, getter=isEditable) BOOL editable;
大多數(shù)情況下,當(dāng)你使用一個(gè)聲明的屬性的時(shí)候,你同樣需要 synthesize 一個(gè)相對(duì)應(yīng)的實(shí)例變量。
確保實(shí)例變量的名字簡(jiǎn)明的描述存儲(chǔ)的屬性。通常情況下,你不能直接訪問(wèn)實(shí)例變量;而是要通過(guò)讀寫(xiě)方法來(lái)訪問(wèn)(你可以在init和dealloc方法中直接訪問(wèn)實(shí)例變量)。為了更加顯著,可以采用下劃線來(lái)命名實(shí)例變量,例如:
@implementation MyClass {BOOL _showsTitle; }如果你通過(guò)使用一個(gè)聲明屬性來(lái)synthesize一個(gè)實(shí)例變量的話,在@synthesize語(yǔ)句中指定實(shí)例變量的名字。
@implementation MyClass @synthesize showsTitle=_showsTitle; @end當(dāng)向類中添加實(shí)例變量的時(shí)候,需要考慮以下幾點(diǎn):
-
避免直接聲明公共的實(shí)例變量
開(kāi)發(fā)者應(yīng)當(dāng)關(guān)注的是對(duì)象的接口,而不是如何存儲(chǔ)數(shù)據(jù)的細(xì)節(jié)。你可以通過(guò)使用聲明屬性以及synthesize相關(guān)的實(shí)例變量。
-
如果你需要聲明一個(gè)實(shí)例變量,避免用@private或者@protected來(lái)聲明。
如果您希望您的類被子類化,并且這些子類需要直接訪問(wèn)數(shù)據(jù),請(qǐng)使用@protected。
-
如果一個(gè)實(shí)例變量是一個(gè)類實(shí)例的可訪問(wèn)屬性,確保你給他寫(xiě)了讀寫(xiě)方法(如果可能,請(qǐng)使用聲明屬性)。
常量
常量的命名規(guī)則根據(jù)常量的創(chuàng)建方式而有所不同。
枚舉常量
- 對(duì)具有整數(shù)值的相關(guān)常量組使用枚舉。
- 枚舉常量和類型定義組的命名約定遵循函數(shù)的命名(參見(jiàn)函數(shù)命名)。以下例子來(lái)自 NSMatrix.h:typedef enum _NSMatrixMode {NSRadioModeMatrix = 0,NSHighlightModeMatrix = 1,NSListModeMatrix = 2,NSTrackModeMatrix = 3 } NSMatrixMode; 注意類型定義的標(biāo)簽(例如上面的_NSMatrixMode)是不需要的。
- 你可以創(chuàng)建一個(gè)諸如位掩碼的沒(méi)有名字的枚舉類型。例如:enum {NSBorderlessWindowMask = 0,NSTitledWindowMask = 1 << 0,NSClosableWindowMask = 1 << 1,NSMiniaturizableWindowMask = 1 << 2,NSResizableWindowMask = 1 << 3 };
通過(guò)const定義的常量
-
使用const為浮點(diǎn)值創(chuàng)建常量。如果常量與其他常量無(wú)關(guān),則可以使用const創(chuàng)建整數(shù)常量;否則,請(qǐng)使用枚舉。
-
下面是一個(gè)const常量的命名格式的例子:
const float NSLightGray;如同常量枚舉一樣,對(duì)于函數(shù)的命名約定也是一樣的(參見(jiàn)函數(shù)命名)。
其他類型的常量
-
通常,不要使用#define預(yù)處理程序命令來(lái)創(chuàng)建常量。對(duì)于整數(shù)常量,使用枚舉;對(duì)于浮點(diǎn)常量,使用const限定符,如上所述。
-
可以用大寫(xiě)符號(hào)做標(biāo)記,這樣預(yù)處理器就可以判斷代碼是否需要被處理。例如:
#ifdef DEBUG -
注意,由編譯器定義的宏在頭部和尾部有雙下劃線。例如:
__MACH__ -
對(duì)于通知名和字典鍵,我們可以定義字符串常量。通過(guò)字符串常量,你可以確保編譯器檢驗(yàn)指定的正確的值(是指執(zhí)行拼寫(xiě)檢查)Cocoa框架提供許多字符串常量的例子,例如:
APPKIT_EXTERN NSString *NSPrintCopies;實(shí)際上,NSString的值是賦值給一個(gè)實(shí)現(xiàn)文件中的常量的。(請(qǐng)注意,在Objective-C中,APPKIT_EXTERN宏是全局變量。)
通知和異常
通知和異常的命名約定遵守同樣的規(guī)則。但是又有他們自己推薦的使用規(guī)則。
通知
如果一個(gè)類有一個(gè)代理,大多數(shù)的通知有可能通過(guò)代理中定義的代理方法來(lái)接收的。這些通知的名稱應(yīng)反映相應(yīng)的委托方法。例如,一個(gè)全局的 NSApplication代理對(duì)象自動(dòng)注冊(cè)接收一個(gè)applicationDidBecomeActive: 的消息,當(dāng)application任何時(shí)候發(fā)送一個(gè)NSApplicationDidBecomeActiveNotification。
通知是通過(guò)全局的NSString對(duì)象來(lái)標(biāo)識(shí)的,以以下方式來(lái)組合名字:
[Name of associated class] + [Did | Will] + [UniquePartOfName] + Notification例如:
NSApplicationDidBecomeActiveNotification NSWindowDidMiniaturizeNotification NSTextViewDidChangeSelectionNotification NSColorPanelColorDidChangeNotification異常
盡管你可以選擇任意意圖來(lái)使用異常(就是說(shuō)NSException類和相關(guān)函數(shù)提供的機(jī)制)但是Cocoa保留一些編程錯(cuò)誤的異常,例如:數(shù)組索引越界異常。Cocoa不使用異常來(lái)處理常規(guī)的預(yù)期錯(cuò)誤情況。對(duì)于這些情況,請(qǐng)使用返回值,例如nil,NULL,NO或錯(cuò)誤代碼的返回值。更多細(xì)節(jié),請(qǐng)參見(jiàn)Error Handling Programming Guide。
異常是通過(guò)全局的NSString對(duì)象來(lái)標(biāo)識(shí)的,以以下方式來(lái)組合名字:
[Prefix] + [UniquePartOfName] + Exception名稱的唯一部分應(yīng)該將組成單詞組合在一起并將每個(gè)單詞的首字母大寫(xiě)。以下是一些例子:
NSColorListIOException NSColorListNotEditableException NSDraggingException NSFontUnavailableException NSIllegalSelectorException可接受的縮寫(xiě)和縮略語(yǔ)
一般來(lái)說(shuō),你在設(shè)計(jì)你的編程接口的時(shí)候,不應(yīng)當(dāng)縮寫(xiě)名字(參見(jiàn)一般原則)。然而,以下列舉的縮寫(xiě)詞已經(jīng)創(chuàng)建并且在過(guò)去使用了很久,所以你可以繼續(xù)使用他。這里有額外的兩件事情需要注意:
- 簡(jiǎn)寫(xiě)格式和在標(biāo)準(zhǔn)的C庫(kù)中長(zhǎng)期使用的格式相同的,例如:“alloc”和“getc”是允許的。
- 你在參數(shù)名中可以更加自由的使用簡(jiǎn)寫(xiě)(例如:imageRep, col (column的簡(jiǎn)寫(xiě)), obj, 和 otherWin)。
| alloc | Allocate 分配 |
| alt | Alternate 輪流的 |
| app | Application 應(yīng)用 例如,全局的應(yīng)用對(duì)象NSApp。然而在代理方法、通知等地方,還是用全拼“application”。 |
| calc | Calculate 計(jì)算 |
| dealloc | Deallocate 取消分配 |
| func | Function 函數(shù) |
| horiz | Horizontal 水平 |
| info | Information 信息 |
| init | Initialize 初始化 用戶初始化對(duì)象方法中 |
| max | Maximum 最大 |
| min | Minimum 最小 |
| msg | Message 消息 |
| nib | Interface Builder archive 界面生成器歸檔文件 |
| pboard | Pasteboard 剪切板(僅在常量中使用) |
| rect | Rectangle 矩形 |
| Rep | Representation 表現(xiàn)(在類名中使用,例如NSBitmapImageRep)。 |
| temp | Temporary 臨時(shí)的 |
| vert | Vertical 垂直的 |
你可以使用已經(jīng)在計(jì)算機(jī)工業(yè)領(lǐng)域非常常見(jiàn)的縮寫(xiě)詞和首字母大寫(xiě)詞。以下是一些比較有名的縮寫(xiě)詞:
ASCIIPDFXMLHTMLURLRTFHTTPTIFFJPGPNGGIFLZWROMRGBCMYKMIDIFTP框架開(kāi)發(fā)者的技巧和小結(jié)
框架開(kāi)發(fā)人員在編寫(xiě)代碼時(shí)必須比其他開(kāi)發(fā)人員更加謹(jǐn)慎。很多的客戶端應(yīng)用都會(huì)鏈接到他們的框架中,正是因?yàn)檫@樣廣泛的暴露,任何框架的缺陷,都會(huì)放大到整個(gè)系統(tǒng)。下面的內(nèi)容討論一些你可以采納的編程技巧,用來(lái)確保你的框架的效率和完整性。
備注:一些技巧不僅僅局限于框架。你也可以應(yīng)用到應(yīng)用開(kāi)發(fā)中。
初始化
以下是包含了框架初始化的意見(jiàn)和建議。
類初始化
+initialize方法為您提供了一個(gè)位置,可以在調(diào)用類的任何其他方法之前懶惰地執(zhí)行一次代碼。通常被用來(lái)設(shè)置類的版本號(hào)(參見(jiàn)版本和兼容性)。
運(yùn)行時(shí)將+initialize方法發(fā)送到繼承鏈中的每個(gè)類,即使它尚未實(shí)現(xiàn)它。因此它可能不止一次地調(diào)用類的+initialize方法(例如,如果子類沒(méi)有實(shí)現(xiàn)它)。通常,您希望初始化代碼只執(zhí)行一次。確保這種情況發(fā)生的一種方法是使用dispatch_once():
+ (void)initialize {static dispatch_once_t onceToken = 0;dispatch_once(&onceToken, ^{// the initializing code} }備注:因?yàn)檫\(yùn)行時(shí)會(huì)發(fā)送初始化給每一個(gè)類,很有可能initialize在子類的上下文環(huán)境中調(diào)用。如果子類沒(méi)有實(shí)現(xiàn)initialize,然后這個(gè)調(diào)用會(huì)傳到父類。如果你需要在相關(guān)的類的上下文中執(zhí)行初始化,你可以用以下檢查替代 dispatch_once()的使用會(huì)更好:
if (self == [NSFoo class]) {// the initializing code }絕不要顯示的調(diào)用initialize方法。如果你想要觸發(fā)初始化,調(diào)用一些無(wú)害的方法,例如:
[NSImage self];指定的初始化函數(shù)
指定的初始化函數(shù)是調(diào)用父類的init方法的類的init方法。(其它初始化器調(diào)用類定義的初始化方法)。每個(gè)公共類都應(yīng)該有一個(gè)或多個(gè)指定的初始化函數(shù)。指定初始化方法的例子有:NSView類的initWithFrame:和NSResponder的init方法。init方法并不意味著需要重寫(xiě),比如NSString類和其它類簇中的抽象類,子類應(yīng)該來(lái)自己實(shí)現(xiàn)。
指定的初始化函數(shù)應(yīng)當(dāng)明確的指定,因?yàn)檫@對(duì)于想要依據(jù)你的類創(chuàng)建子類來(lái)說(shuō)非常重要。子類僅重寫(xiě)指定的初始化函數(shù)。
當(dāng)你要實(shí)現(xiàn)一個(gè)框架的類時(shí),你經(jīng)常需要也實(shí)現(xiàn)它的存檔方法:initWithCoder:和 encodeWithCoder:。注意不要當(dāng)在對(duì)象解歸檔的時(shí)候,在初始化的代碼中執(zhí)行不會(huì)發(fā)生的事情。實(shí)現(xiàn)這一目標(biāo)的一個(gè)好方法是,如果您的類實(shí)現(xiàn)了歸檔,則從您指定的初始化程序和initWithCoder調(diào)用一個(gè)公共例程:(這是一個(gè)指定的初始化函數(shù))。
初始化過(guò)程中的錯(cuò)誤檢測(cè)
一個(gè)設(shè)計(jì)比較好的初始化方法應(yīng)當(dāng)通過(guò)完成以下幾部來(lái)確保正確的檢測(cè)和錯(cuò)誤輸出:
版本和兼容性
向框架添加新類或方法時(shí),通常不必為每個(gè)新功能組指定新版本號(hào)。開(kāi)發(fā)人員通常執(zhí)行(或應(yīng)該執(zhí)行)Objective-C運(yùn)行時(shí)檢查,例如respondsToSelector:以確定某個(gè)功能是否在給定系統(tǒng)上可用。這些運(yùn)行時(shí)測(cè)試是檢查新功能的首選和最動(dòng)態(tài)的方法。
但是,您可以使用多種技術(shù)來(lái)確保正確標(biāo)記每個(gè)新版本的框架,并使其與早期版本盡可能兼容。
框架版本
當(dāng)有一個(gè)新增特性或者bug被修復(fù)時(shí),通過(guò)運(yùn)行時(shí)測(cè)試是不容易檢測(cè)出來(lái)的,你應(yīng)當(dāng)以某種方式告知開(kāi)發(fā)者來(lái)檢測(cè)這種變化。一種方式就是以歸檔的形式來(lái)存儲(chǔ)框架的確切版本號(hào),同時(shí)需要讓開(kāi)發(fā)者可見(jiàn)這些內(nèi)容:
- 在每一個(gè)版本號(hào)下做文檔記錄變化(例如,在發(fā)布備注中)。
- 設(shè)置你框架當(dāng)前的版本號(hào)并且提供一些方式讓它能夠全局訪問(wèn)。你可以通過(guò)Info.plist文件來(lái)存儲(chǔ)你框架的版本號(hào),然后可以通過(guò)這種方式來(lái)訪問(wèn)。
歸檔中的key
如果你的框架對(duì)象需要寫(xiě)入nib文件,他們必須能夠自歸檔。你同樣需要通過(guò)使用歸檔機(jī)制存儲(chǔ)文檔數(shù)據(jù)來(lái)歸檔任何文檔。
你應(yīng)當(dāng)考慮以下關(guān)于歸檔方面的問(wèn)題:
- 如果歸檔中的key丟失了,請(qǐng)求對(duì)應(yīng)的值的話,將會(huì)返回nil、NULL、NO、0或0.0等,取決于請(qǐng)求的數(shù)據(jù)類型。通過(guò)判斷這個(gè)返回值,可以減少你的數(shù)據(jù)輸出。另外,你可以確認(rèn)這個(gè)key有沒(méi)有被寫(xiě)入歸檔。
- 編碼和解碼方法都可以做到確保向后兼容性。例如一個(gè)類的新版本的編碼方法可能會(huì)通過(guò)使用key寫(xiě)入新的值,但是可能仍然返回舊的字段以便舊版本的類仍然知道這個(gè)對(duì)象。另外,解碼方法想要通過(guò)一些可能的方式來(lái)處理丟失的值來(lái)保持新版本的靈活性。
- 對(duì)于框架類的歸檔key的一個(gè)推薦的命名約定就是以針對(duì)于其他框架API元素的前綴并且使用實(shí)例變量的名字。這樣確保命名不會(huì)和其他任何父類或子類的名字沖突。
- 如果你有一個(gè)工具函數(shù)輸出一個(gè)基本的數(shù)據(jù)類型(換言之,這個(gè)值不是對(duì)象),確保使用一個(gè)唯一的key。例如,如果你有一個(gè)archiveRect程序來(lái)歸檔舉行,需要傳入key參數(shù),你可以使用它。或者,如果它輸出多個(gè)值(例如,四個(gè)浮點(diǎn)數(shù)據(jù)),應(yīng)當(dāng)在給定的key上追加自己唯一的位。
- 按照原樣來(lái)歸檔位字段是很危險(xiǎn)的,因?yàn)檫@個(gè)和編譯器以及字節(jié)順序依賴有關(guān)。你僅能在對(duì)于優(yōu)化的原因的情況下歸檔位字段,例如,需要大量多次的的位輸出。參見(jiàn)位字段。
異常和錯(cuò)誤
大多數(shù)Cocoa框架方法都不會(huì)強(qiáng)制開(kāi)發(fā)人員捕獲和處理異常。這是因?yàn)楫惓2皇亲鳛閳?zhí)行的正常部分引發(fā)的,并且通常不用于傳達(dá)預(yù)期的運(yùn)行時(shí)或用戶錯(cuò)誤。這些錯(cuò)誤的示例包括:
- 文件沒(méi)有找到
- 沒(méi)有此用戶
- 在應(yīng)用中視圖打開(kāi)一個(gè)錯(cuò)誤的文檔類型
- 轉(zhuǎn)化字符串到特定編碼格式錯(cuò)誤
然而,Cocoa對(duì)于以下情況會(huì)產(chǎn)生異常來(lái)指明程序或者邏輯錯(cuò)誤:
- 數(shù)據(jù)越界訪問(wèn)
- 嘗試改變不可變的對(duì)象
- 錯(cuò)誤的參數(shù)類型
期望開(kāi)發(fā)人員在測(cè)試期間捕獲這些錯(cuò)誤并在發(fā)布應(yīng)用程序之前解決它們;因此,應(yīng)用程序不需要在運(yùn)行時(shí)處理異常。如果一個(gè)異常往外擴(kuò)散,應(yīng)用沒(méi)有捕獲它,高級(jí)別的默認(rèn)處理器通常會(huì)處理它,并且會(huì)報(bào)告異常,然后讓它們繼續(xù)執(zhí)行。開(kāi)發(fā)人員可以選擇將此默認(rèn)異常捕獲器替換為提供更多錯(cuò)誤詳細(xì)信息的異常捕獲器,并且提供一個(gè)可選項(xiàng)來(lái)保存數(shù)據(jù)并且退出應(yīng)用程序。
錯(cuò)誤是Cocoa框架與其他軟件庫(kù)不同的另一個(gè)領(lǐng)域。Cocoa方法通常不返回錯(cuò)誤代碼。在存在一個(gè)合理或可能的錯(cuò)誤原因的情況下,這些方法依賴于對(duì)布爾或?qū)ο?#xff08;nil / non-nil)返回值的簡(jiǎn)單測(cè)試;記錄NO或零返回值的原因。您不應(yīng)該使用錯(cuò)誤代碼來(lái)指示要在運(yùn)行時(shí)處理的編程錯(cuò)誤,而是引發(fā)異常,或者在某些情況下只記錄錯(cuò)誤而不引發(fā)異常。
例如,NSDictionary的objectForKey:方法要么返回找到的對(duì)象,要么返回nil,如果它找不到對(duì)象。NSArray的objectAtIndex:方法不會(huì)返回nil(除非重寫(xiě)一般語(yǔ)言約定,將任何信息轉(zhuǎn)換成nil,導(dǎo)致返回nil),因?yàn)镹SArray對(duì)象不能存儲(chǔ)nil值,并且根據(jù)定義,任何越界訪問(wèn)都是一個(gè)編程錯(cuò)誤,應(yīng)該導(dǎo)致異常。許多初始化方法會(huì)因?yàn)橥ㄟ^(guò)提供的參數(shù)不能夠初始化,從而導(dǎo)致返回nil。
在少數(shù)情況下,一個(gè)方法有一個(gè)返回多個(gè)不同的錯(cuò)誤代碼,應(yīng)當(dāng)用引用參數(shù)來(lái)指定它,返回一個(gè)錯(cuò)誤的代碼,一個(gè)本地話的錯(cuò)誤字符串,或者其他的描述錯(cuò)誤的信息。例如,你肯能需要返回一個(gè)NSError對(duì)象來(lái)表示錯(cuò)誤;可以查看框架中的NSError.h頭文件來(lái)獲取細(xì)節(jié)。這個(gè)參數(shù)一般來(lái)說(shuō)是一個(gè)直接返回的BOOL或者nil。該方法還應(yīng)遵守以下約定:所有引用參數(shù)都是可選的,因此如果發(fā)件人不希望了解錯(cuò)誤,則允許發(fā)送者為錯(cuò)誤代碼參數(shù)傳遞NULL。
框架數(shù)據(jù)
如何處理框架數(shù)據(jù)會(huì)對(duì)性能,跨平臺(tái)兼容性和其他目的產(chǎn)生影響。這部分討論涉及的框架數(shù)據(jù)的技巧。
常量數(shù)據(jù)
出于性能原因,最好將盡可能多的框架數(shù)據(jù)標(biāo)記為常量,因?yàn)檫@樣做會(huì)減小Mach-O二進(jìn)制文件的__DATA段的大小。非const的全局和靜態(tài)數(shù)據(jù)最終會(huì)出現(xiàn)在__DATA section的__DATA段中。這種數(shù)據(jù)占用了使用框架的應(yīng)用程序的每個(gè)運(yùn)行實(shí)例中的內(nèi)存。雖然額外的500字節(jié)(舉個(gè)例子)可能看起來(lái)不那么糟糕,但它可能會(huì)導(dǎo)致所需頁(yè)數(shù)增加 - 每個(gè)應(yīng)用程序額外增加4千字節(jié)。
您應(yīng)該將任何常量數(shù)據(jù)標(biāo)記為const。如果block中沒(méi)有char *指針,會(huì)導(dǎo)致數(shù)據(jù)處在__TEXT段中(這里會(huì)使之成為真正的常量);否則的話,它處于__DATA段,但是卻不能寫(xiě)入(除非預(yù)綁定沒(méi)有完成或者通過(guò)在加載時(shí)二進(jìn)制的偏移來(lái)改變它)。
您應(yīng)該初始化靜態(tài)變量以確保它們合并到__DATA段的__data部分而不是__bss部分。如果沒(méi)有明顯的值用于初始化,請(qǐng)使用0,NULL,0.0或任何適當(dāng)?shù)闹怠?/p>
位段
針對(duì)位段使用有符號(hào)的值,特別是一位的位段,這樣會(huì)導(dǎo)致如果代碼將這個(gè)值作為boolean值,會(huì)出現(xiàn)未定義行為。一位位域應(yīng)始終為無(wú)符號(hào)。因?yàn)榭梢源鎯?chǔ)在這樣的位域中的唯一值是0和-1(取決于編譯器實(shí)現(xiàn)),所以將該位域與1進(jìn)行比較是錯(cuò)誤的。例如,如果您在代碼中遇到類似這樣的內(nèi)容:
BOOL isAttachment:1; int startTracking:1;您應(yīng)該將類型更改為unsigned int。
另外一個(gè)和位段相關(guān)的內(nèi)容是歸檔。一般來(lái)說(shuō),你不能以位段本身的格式來(lái)寫(xiě)入到磁盤(pán)或者歸檔中,因?yàn)楫?dāng)在另外一個(gè)架構(gòu)或者其它編譯器上讀取的時(shí)候,格式可能不同。
內(nèi)存分配
在框架代碼中,避免全部?jī)?nèi)存分配是最好的課程。如果由于某種原因需要臨時(shí)緩沖區(qū),通常使用棧比分配緩沖區(qū)更好。但是,堆棧的大小有限(通常總共512KB),因此使用堆棧的決定取決于您需要的函數(shù)和緩沖區(qū)的大小。通常,如果buffer大小是1000bytes(或者M(jìn)AXPATHLEN)或者更小,可以使用棧。
一個(gè)改進(jìn)是開(kāi)始使用棧,但如果大小要求超出棧緩沖區(qū)大小,則切換到堆緩沖區(qū)中。以下有例子:
#define STACKBUFSIZE (1000 / sizeof(YourElementType))YourElementType stackBuffer[STACKBUFSIZE]; YourElementType *buf = stackBuffer; int capacity = STACKBUFSIZE; // In terms of YourElementType int numElements = 0; // In terms of YourElementTypewhile (1) {if (numElements > capacity) { // Need more roomint newCapacity = capacity * 2; // Or whatever your growth algorithm isif (buf == stackBuffer) { // Previously using stack; switch to allocated memorybuf = malloc(newCapacity * sizeof(YourElementType));memmove(buf, stackBuffer, capacity * sizeof(YourElementType));} else { // Was already using malloc; simply reallocbuf = realloc(buf, newCapacity * sizeof(YourElementType));}capacity = newCapacity;}// ... use buf; increment numElements ...}// ...if (buf != stackBuffer) free(buf);對(duì)象比較
你應(yīng)當(dāng)意識(shí)到泛型的對(duì)象比較方法isEqual: 和對(duì)象相關(guān)的比較方法,例如isEqualToString:方法之間的重要區(qū)別。isEqual: 方法允許你傳入任意對(duì)象作為參數(shù),并且如果對(duì)象不是同一個(gè)類會(huì)返回NO。諸如isEqualToString: 和isEqualToArray:方法通常假設(shè)參數(shù)是指定的類型(也就是接收者的類型)。因此,它們不執(zhí)行類型檢查,因此它們更快但不安全。對(duì)于從外部源檢索的值,例如應(yīng)用程序的信息屬性列表(Info.plist)或首選項(xiàng),使用isEqual:是首選,因?yàn)樗踩?當(dāng)類型已知時(shí),請(qǐng)使用isEqualToString:代替。
和isEqual:方法相關(guān)的一點(diǎn)就是它和hash方法有關(guān)。對(duì)象一個(gè)最基本的不變的地方就是被放入一個(gè)基于哈希的例如NSDictionary或NSSetCocoa集合中,如果[A isEqual:B] == YES,那么[A hash] == [B hash]。如果你重寫(xiě)你的類的isEqual:方法,你應(yīng)當(dāng)也要重寫(xiě)hash方法來(lái)維持這一個(gè)不變的條件。默認(rèn)的isEqual:方法尋找和每一個(gè)對(duì)象地址相等的指針,并且hash方法返回的hash值是基于每一個(gè)對(duì)象的地址,所以還是保持了這個(gè)不變性。
總結(jié)
- 上一篇: mpeg4 码流格式及判断关键帧
- 下一篇: 笔试题集锦