談?wù)刬OS中的命名規(guī)范

歡迎到我的 個(gè)人博客 http://liumh.com 瀏覽此文

本文談?wù)?iOS 開(kāi)發(fā)中的命名規(guī)范,主要涉及常量命名、枚舉命名皿曲、類及其方法命名,以及分類及其方法命名吴侦。如果你找的是官網(wǎng)的編碼規(guī)范屋休,請(qǐng)移步: Coding Guidelines for Cocoa。當(dāng)然本文會(huì)講一些官網(wǎng)沒(méi)有的東西备韧。

  • 常量命名
  • 用枚舉表示狀態(tài)劫樟、選項(xiàng)、狀態(tài)碼
  • 類及其方法命名
  • 分類及其方法命名

常量命名

iOS 開(kāi)發(fā)中,肯定避免不了要命名一些常量毅哗,那么听怕,我們應(yīng)該怎樣來(lái)命名常量呢捧挺?

在討論上述問(wèn)題前虑绵,先來(lái)了解定義常量的兩種方式。

第一種闽烙,使用 #define 預(yù)處理定義常量翅睛。例如:

#define ANIMATION_DURATION 0.3

定義一個(gè) ANIMATION_DURATION 常量來(lái)表示 UI 動(dòng)畫的一個(gè)常量時(shí)間,這樣黑竞,代碼中所有使用 ANIMATION_DURATION 的地方都會(huì)被替換成 0.3捕发,但是這樣定義的常量無(wú)類型信息,且如果你在調(diào)試時(shí)想要查看 ANIMATION_DURATION 的值卻無(wú)從下手很魂,因?yàn)樵陬A(yù)處理階段ANIMATION_DURATION 就已經(jīng)被替換了扎酷,不便于調(diào)試。因此遏匆,棄用這種方式定義常量法挨。

第二種,使用類型常量幅聘。將上面的預(yù)處理定義常量修改成類型常量:

static const NSTimeInterval kAnimationDuration = 0.3;

這樣就為常量帶入了類型信息凡纳,那么定義類型常量又有什么規(guī)范呢?

  • 對(duì)于局限于某編譯單元(實(shí)現(xiàn)文件)的常量帝蒿,通常以字符k開(kāi)頭荐糜,例如上文中的 kAnimationDuration,且需要以 static const 修飾葛超,例如:

static const NSTimeInterval kAnimationDuration = 0.3;

  • 對(duì)于定義于類頭文件的常量暴氏,外部可見(jiàn),則通常以定義該常量所在類的類名開(kāi)頭绣张,例如 EOCViewClassAnimationDuration, 仿照蘋果風(fēng)格偏序,在頭文件中進(jìn)行 extern 聲明,在實(shí)現(xiàn)文件中定義其值:
EOCViewClass.h

extern const NSTimeInterval EOCViewClassAnimationDuration;


EOCViewClass.m

const NSTimeInterval EOCViewClassAnimationDuration = 0.3;

對(duì)于字符串常量胖替,則會(huì)像這樣:

EOCViewClass.h

extern NSString *const EOCViewClassStringConstant;


EOCViewClass.m

NSString *const EOCViewClassStringConstant = @"EOCStringConstant";

常量定義是從右往左解讀研儒,上面的示例中就是定義了一個(gè)常量指針,其指向一個(gè) NSString 對(duì)象, 這樣該常量就不會(huì)被隨意修改独令。至于這種暴露出來(lái)的類常量最前面是否加上字母k, 可以根據(jù)自己習(xí)慣在團(tuán)隊(duì)中進(jìn)行約定端朵,因?yàn)閺?iOS 的接口中我看到這兩種情況都有, 如

NSString *const UIApplicationLaunchOptionsRemoteNotificationKey;
NSString *const UIApplicationLaunchOptionsLocalNotificationKey;

還有:

NSString *const kCAAnimationCubic;
NSString *const kCAAnimationCubicPaced;

用枚舉表示狀態(tài)、選項(xiàng)燃箭、狀態(tài)碼

項(xiàng)目中冲呢,可用枚舉來(lái)表示一系列的狀態(tài)、選項(xiàng)和狀態(tài)碼招狸。例如 iOS SDK 中表示 UICollectionView 滑動(dòng)方向的枚舉定義如下:

typedef NS_ENUM(NSInteger, UICollectionViewScrollDirection) {
    UICollectionViewScrollDirectionVertical,
    UICollectionViewScrollDirectionHorizontal
};

或者定義 UITableView Style 的枚舉:

typedef NS_ENUM(NSInteger, UITableViewStyle) {
    UITableViewStylePlain,      // regular table view
    UITableViewStyleGrouped     // preferences style table view
};

從這里可以看出敬拓,定義的枚舉類型名稱應(yīng)以 2~3 個(gè)大寫字母開(kāi)頭邻薯,而這通常與項(xiàng)目設(shè)置的類文件前綴相同厕诡,跟隨其后的命名應(yīng)采用駝峰命名法則,命名應(yīng)準(zhǔn)確表述枚舉表示的意義营勤,枚舉中各個(gè)值都應(yīng)以定義的枚舉類型開(kāi)頭灵嫌,其后跟隨各個(gè)枚舉值對(duì)應(yīng)的狀態(tài)、選項(xiàng)或者狀態(tài)碼葛作。

對(duì)于需要以按位或操作來(lái)組合的枚舉都應(yīng)使用 NS_OPTIONS 宏來(lái)定義寿羞,例如 SDK 中:

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

這樣定義的選項(xiàng)能夠以 按位或操作符 來(lái)進(jìn)行組合,枚舉中每個(gè)值均可啟用或者禁用某一選項(xiàng)赂蠢,在使用時(shí)绪穆,可以使用 按位與操作符 來(lái)檢測(cè)是否啟用了某一選項(xiàng),如下:

UIViewAutoresizing resizing = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

if (resizing & UIViewAutoresizingFlexibleWidth) {
// UIViewAutoresizingFlexibleWidth is set

}

另外虱岂,我們可能使用 switch 語(yǔ)句時(shí)玖院,會(huì)在最后加上 default 分支,但是若用枚舉定義狀態(tài)機(jī)量瓜,則最好不要使用 default 分支司恳,因?yàn)槿绻院笤偌恿艘环N狀態(tài),那么編譯器就會(huì)發(fā)出警告绍傲,提示新加入的狀態(tài)并未在 switch 分支中處理扔傅。假如寫上了 default 分支,那么它就會(huì)處理這個(gè)新?tīng)顟B(tài)烫饼,從而導(dǎo)致編譯器不發(fā)出警告猎塞,用 NS_ENUM 定義其他枚舉類型時(shí)也要注意此問(wèn)題。例如在定義代表 UI 元素樣式的枚舉時(shí)杠纵,通常要確保 switch 語(yǔ)句能正確處理所有樣式荠耽。

總結(jié)一下:

  • 應(yīng)該用枚舉來(lái)表示狀態(tài)機(jī)的狀態(tài)、傳遞給方法的選項(xiàng)以及狀態(tài)碼等值比藻,給這些值起個(gè)易懂的名字铝量。
  • 如果把傳遞給某個(gè)方法的選項(xiàng)表示為枚舉類型,而多個(gè)選項(xiàng)又可同時(shí)使用银亲,那么就將各選項(xiàng)值定義為 2 的冪慢叨,以便通過(guò)按位或操作將其組合起來(lái)。
  • 用 NS_ENUM 與 NS_OPTIONS 宏來(lái)定義枚舉類型务蝠,并指明其底層數(shù)據(jù)類型拍谐。這樣就可以確保枚舉是用開(kāi)發(fā)者所選的底層數(shù)據(jù)類型實(shí)現(xiàn)出來(lái)的,而不是采用編譯器所選的類型践瓷。
  • 在處理枚舉類型的 switch 語(yǔ)句中不要實(shí)現(xiàn) default 分支亡蓉。這樣加入新的枚舉值之后崖面,編譯器就會(huì)發(fā)出警告提示梯影,switch 還有未處理的枚舉值甲棍。

類及其方法命名

Objective-C 沒(méi)有其他語(yǔ)言那種內(nèi)置的命名空間(namespace)機(jī)制感猛。因此奢赂,我們?cè)谄鹈麜r(shí)要設(shè)法避免潛在的命名沖突膳灶,否則很容易就重名了序厉。避免此問(wèn)題的唯一方法就是變相實(shí)現(xiàn)命名空間: 為所有名稱都加上適當(dāng)前綴毕箍。所選前綴可以是與公司而柑、應(yīng)用程序或者二者皆有關(guān)聯(lián)的名字媒咳。使用 Cocoa 和 Cocoa Touch 創(chuàng)建應(yīng)用程序時(shí)一定要注意,Apple 宣傳其保留使用所有"兩個(gè)字母前綴"(tow-letter prefixed)的權(quán)利恨搓。所以你自己選用的前綴應(yīng)該是三個(gè)字母的常拓。你可以在蘋果官網(wǎng) Class Names Must Be Unique Across an Entire App 看到上述說(shuō)明:

In order to keep class names unique, the convention is to use prefixes on all classes. You’ll have noticed that Cocoa and Cocoa Touch class names typically start either with NS or UI. Two-letter prefixes like these are reserved by Apple for use in framework classes.

Your own classes should use three letter prefixes. These might relate to a combination of your company name and your app name, or even a specific component within your app.

You should also name your classes using a noun that makes it clear what the class represents, like these examples from Cocoa and Cocoa Touch:

| NSWindow | CAAnimation | NSWindowController | NSManagedObjectContext

另外弄抬,在文檔 Coding Guidelines for Cocoa 中提到:

Use prefixes when naming classes, protocols, functions, constants, and typedef structures. Do not use prefixes when naming methods; methods exist in a name space created by the class that defines them. Also, don’t use prefixes for naming the fields of a structure.

這里需要說(shuō)明兩點(diǎn):

  • 上述所說(shuō)的functions指的是純 C 函數(shù)。對(duì)于純 C 函數(shù)和全局變量懊亡,不論其處于頭文件或者其實(shí)現(xiàn)文件中乎串,在編譯好的目標(biāo)文件中叹誉,這些名稱要算作"頂級(jí)符號(hào)"(top-level symbol)的钧唐。因此我們總應(yīng)該為這種 C 函數(shù)的名字加上前綴匠襟。通常情況下宅此,這類 C 函數(shù)我們可以以定義其類的名字作為前綴父腕。這樣璧亮,在調(diào)試時(shí)枝嘶,若此符號(hào)出現(xiàn)在棧回溯信息中及刻,則很容易就能判明問(wèn)題源自哪塊代碼缴饭。例如:
ACLSoundPlayer.h

#import <Foundation/Foundation.h>

@interface ACLSoundPlayer : NSObject

@end


ACLSoundPlayer.m

#import "ACLSoundPlayer.h"
#import <AudioToolbox/AudioToolbox.h>

void ACLSoundPlayerCompletion(SystemSoundID ssID, void *clientData) {

}

@implementation ACLSoundPlayer

@end
  • 上述引用說(shuō)到不應(yīng)該為 Objective-C methods 添加前綴颗搂,我覺(jué)得應(yīng)該添加一個(gè)例外丢氢,當(dāng)我們定義分類中的方法時(shí)疚察,則總應(yīng)該為其添加前綴稍浆,這會(huì)在下一條詳細(xì)說(shuō)明衅枫。

最后一種情況弦撩,若為第三庫(kù)編寫自己的代碼益楼,并準(zhǔn)備將其發(fā)布為程序庫(kù)供他人開(kāi)發(fā)應(yīng)用程序所用時(shí)感凤,你應(yīng)該給你所用的那份第三方庫(kù)代碼都加上你自己的前綴。為便于說(shuō)明屠橄,假如你要發(fā)布的程序庫(kù)叫 EOCLibrary礁哄,你所使用的第三方庫(kù)叫 XYZLibrary桐绒,則你應(yīng)該把你使用的 XYZLibrary 中所有名字都冠以 EOC, 成為 EOCXYZLibrary, 原因如下:

  • 你的程序所包含的那個(gè)第三方庫(kù)也許還會(huì)為應(yīng)用程序本身所引入。
  • 你可能會(huì)想劳翰,讓應(yīng)用程序本身不要直接引入 XYZLibrary佳簸,改用 EOCLibrary 中使用的那個(gè)生均,但是马胧,應(yīng)用程序也許還會(huì)引入另一個(gè)名為 ABCLibrary 的第三方庫(kù)佩脊,而該庫(kù)中又包含了 XYZLibrary威彰。此時(shí)歇盼,如果你和 ABCLibrary 的作者都不給各自所用的 XYZLibrary 加前綴豹缀,那么應(yīng)用程序依然會(huì)出現(xiàn)重復(fù)符號(hào)錯(cuò)誤邢笙。
  • 你的庫(kù)里所引用的第三方庫(kù)是 X 版本的,而應(yīng)用程序卻需要引用第三庫(kù)的 Y 版本的功能筐骇。

對(duì)于類中的方法命名,應(yīng)遵循以下規(guī)則:

  • 如果方法的返回值是新建的江滨,那么方法名的首個(gè)詞應(yīng)是返回值的類型铛纬,例如: +stringWithString:。除非前面還有修飾語(yǔ)唬滑,例如 localizedString告唆。屬性的存取方法不遵循這種命名方式棺弊。
  • BOOL屬性應(yīng)加 is 前綴。如果某方法返回非屬性的 Boolean 值擒悬,那么應(yīng)該根據(jù)你功能模她,選用 has 或 is 當(dāng)前綴。

分類及其方法命名

分類機(jī)制通常用于向無(wú)源碼的既有類中新增功能懂牧。分類中的方法是直接加在類里面的躯保,它們就好比這個(gè)類固有的方法,將分類方法加入類中這一操作是在運(yùn)行期系統(tǒng)加載分類時(shí)完成的振惰。運(yùn)行期系統(tǒng)會(huì)把分類中所實(shí)現(xiàn)的每個(gè)方法都加入類的方法列表中桶蛔。如果類中本來(lái)就有此方法碟婆,而分類中又實(shí)現(xiàn)了一次公给,那么分類中的方法會(huì)覆蓋原來(lái)那一份實(shí)現(xiàn)代碼。實(shí)際上可能會(huì)發(fā)生很多次覆蓋加叁,比如某個(gè)分類中的方法覆蓋了"主實(shí)現(xiàn)"中的相關(guān)方法豫柬,而另外一個(gè)分類中的方法又覆蓋了這個(gè)分類中的方法础嫡,多次覆蓋的結(jié)果以最后一個(gè)分類為準(zhǔn)晚唇。當(dāng)有多份實(shí)現(xiàn)時(shí)闽瓢,無(wú)法確定運(yùn)行時(shí)使用的是那份實(shí)現(xiàn)届谈。由這樣引發(fā)的 bug 很難追查摔吏。

那么诗箍,如何來(lái)最大限度的避免這種覆蓋呢?

在 iOS 開(kāi)發(fā)中塑顺,沒(méi)有命名空間的概念糙俗。通常劈彪,我們通過(guò)為項(xiàng)目中所有類命名加上特有的前綴來(lái)實(shí)現(xiàn)命名空間的功能,來(lái)避免可能發(fā)生的與使用第三方庫(kù)中的方法命名相同。同樣的冬骚,這里我們也是為分類只冻,以及分類中的所有方法都加上特定前綴喜德。這個(gè)前綴應(yīng)該與應(yīng)用程序庫(kù)中其他地方所用的前綴相同,通常會(huì)使用公司名或應(yīng)用程序名來(lái)做決定馁蒂。例如來(lái)編寫一個(gè)判斷對(duì)象是否為空的分類方法:

NSObject+ACLNetworkingMethods.h

@interface NSObject (ACLNetworkingMethods)

- (BOOL)acl_isEmptyObject;

@end

這里為分類名以及分類中的方法加上了 ACL 的前綴。注意在方法中,需前綴小寫辑舷。

另外,使用分類時(shí)刚陡,不要刻意覆寫分類中的方法惩妇,尤其是當(dāng)你把代碼發(fā)布為程序庫(kù)供其他開(kāi)發(fā)者使用時(shí),因?yàn)槟銦o(wú)法決定其他開(kāi)發(fā)者需要的是方法哪份實(shí)現(xiàn)筐乳。

總結(jié):

  • 向第三方類中添加分類時(shí)歌殃,總應(yīng)該給分類名稱加上你專有的前綴,前綴須大寫蝙云。
  • 向第三方類中添加分類時(shí)氓皱,總應(yīng)該給分類中的方法名加上你專有的前綴,前綴須小寫勃刨,且以下劃線連接前綴與方法名波材。

歡迎留言交流。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末身隐,一起剝皮案震驚了整個(gè)濱河市廷区,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贾铝,老刑警劉巖隙轻,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異垢揩,居然都是意外死亡玖绿,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門叁巨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)斑匪,“玉大人,你說(shuō)我怎么就攤上這事锋勺∈慈常” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵庶橱,是天一觀的道長(zhǎng)苍姜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)悬包,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任馍乙,我火速辦了婚禮布近,結(jié)果婚禮上垫释,老公的妹妹穿的比我還像新娘。我一直安慰自己撑瞧,他們只是感情好棵譬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著预伺,像睡著了一般订咸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上酬诀,一...
    開(kāi)封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天脏嚷,我揣著相機(jī)與錄音,去河邊找鬼瞒御。 笑死父叙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的肴裙。 我是一名探鬼主播趾唱,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蜻懦!你這毒婦竟也來(lái)了甜癞?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤宛乃,失蹤者是張志新(化名)和其女友劉穎悠咱,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烤惊,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乔煞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了柒室。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渡贾。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖雄右,靈堂內(nèi)的尸體忽然破棺而出空骚,到底是詐尸還是另有隱情,我是刑警寧澤擂仍,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布囤屹,位于F島的核電站,受9級(jí)特大地震影響逢渔,放射性物質(zhì)發(fā)生泄漏肋坚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望智厌。 院中可真熱鬧诲泌,春花似錦、人聲如沸铣鹏。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)诚卸。三九已至葵第,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間合溺,已是汗流浹背卒密。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辫愉,地道東北人栅受。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像恭朗,于是被迫代替她去往敵國(guó)和親屏镊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容