04-禪與 Objective-C 編程藝術(shù)之美化代碼與代碼組織

01-禪與 Objective-C 編程藝術(shù)之條件語(yǔ)句與命名

02-禪與 Objective-C 編程藝術(shù)之類(lèi)

03-禪與 Objective-C 編程藝術(shù)之Categories/Protocols/NSNotification

美化代碼

空格

縮進(jìn)使用 4 個(gè)空格掠哥。 永遠(yuǎn)不要使用 tab, 確保你在 Xcode 的設(shè)置里面是這樣設(shè)置的。
方法的大括號(hào)和其他的大括號(hào)(if/else/switch/while 等) 總是在同一行開(kāi)始,在新起一行結(jié)束。
推薦:

if (user.isHappy) {
    //Do something
}
else {
    //Do something else
}

不推薦:

if (user.isHappy)
{
  //Do something
} else {
  //Do something else
}
  • 方法之間應(yīng)該要有一個(gè)空行來(lái)幫助代碼看起來(lái)清晰且有組織抵代。 方法內(nèi)的空格應(yīng)該用來(lái)分離功能,但是通常不同的功能應(yīng)該用新的方法來(lái)定義恕酸。
  • 優(yōu)先使用 auto-synthesis奉呛。但是如果必要的話(huà), @synthesize and @dynamic
  • 在實(shí)現(xiàn)文件中的聲明應(yīng)該新起一行珊搀。
  • 應(yīng)該總是讓冒號(hào)對(duì)齊冶忱。有一些方法簽名可能超過(guò)三個(gè)冒號(hào),用冒號(hào)對(duì)齊可以讓代碼更具有可讀性境析。即使有代碼塊存在囚枪,也應(yīng)該用冒號(hào)對(duì)齊方法。

推薦:

[UIView animateWithDuration:1.0
                 animations:^{
                     // something
                 }
                 completion:^(BOOL finished) {
                     // something
                 }];

不推薦:

[UIView animateWithDuration:1.0 animations:^{
    // something
} completion:^(BOOL finished) {
    // something
}];

如果自動(dòng)對(duì)齊讓可讀性變得糟糕劳淆,那么應(yīng)該在之前把 block 定義為變量链沼,或者重新考慮你的代碼簽名設(shè)計(jì)。

換行

本指南關(guān)注代碼顯示效果以及在線(xiàn)瀏覽的可讀性沛鸵,所以換行是一個(gè)重要的主題括勺。

舉個(gè)例子:

self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];

一個(gè)像上面的長(zhǎng)行的代碼在第二行以一個(gè)間隔(2個(gè)空格)延續(xù)

self.productsRequest = [[SKProductsRequest alloc]
  initWithProductIdentifiers:productIdentifiers];

括號(hào)

在以下的地方使用 Egyptian風(fēng)格 括號(hào) (譯者注:又稱(chēng) K&R 風(fēng)格缆八,代碼段括號(hào)的開(kāi)始位于一行的末尾,而不是另外起一行的風(fēng)格疾捍。關(guān)于為什么叫做 Egyptian Brackets奈辰,可以參考 http://blog.codinghorror.com/new-programming-jargon/ )

  • 控制語(yǔ)句 (if-else, for, switch)

非 Egyptian 括號(hào)可以用在:

  • 類(lèi)的實(shí)現(xiàn)(如果存在)
  • 方法的實(shí)現(xiàn)

代碼組織

來(lái)自 Mattt Thompson

code organization is a matter of hygiene (代碼組織是衛(wèi)生問(wèn)題)

我們十分贊成這句話(huà)。清晰地組織代碼和規(guī)范地進(jìn)行定義, 是你對(duì)自己以及其他閱讀代碼的人的尊重乱豆。

利用代碼塊

一個(gè) GCC 非常模糊的特性奖恰,以及 Clang 也有的特性是,代碼塊如果在閉合的圓括號(hào)內(nèi)的話(huà)宛裕,會(huì)返回最后語(yǔ)句的值

NSURL *url = ({
    NSString *urlString = [NSString stringWithFormat:@"%@/%@", baseURLString, endpoint];
    [NSURL URLWithString:urlString];
});

Pragma

Pragma Mark

#pragma mark -是一個(gè)在類(lèi)內(nèi)部組織代碼并且?guī)椭惴纸M方法實(shí)現(xiàn)的好辦法瑟啃。 我們建議使用 #pragma mark - 來(lái)分離:

  • 不同功能組的方法
  • protocols 的實(shí)現(xiàn)
  • 對(duì)父類(lèi)方法的重寫(xiě)
- (void)dealloc { /* ... */ }
- (instancetype)init { /* ... */ }

#pragma mark - View Lifecycle (View 的生命周期)

- (void)viewDidLoad { /* ... */ }
- (void)viewWillAppear:(BOOL)animated { /* ... */ }
- (void)didReceiveMemoryWarning { /* ... */ }

#pragma mark - Custom Accessors (自定義訪(fǎng)問(wèn)器)

- (void)setCustomProperty:(id)value { /* ... */ }
- (id)customProperty { /* ... */ }

#pragma mark - IBActions  

- (IBAction)submitData:(id)sender { /* ... */ }

#pragma mark - Public

- (void)publicMethod { /* ... */ }

#pragma mark - Private

- (void)zoc_privateMethod { /* ... */ }

#pragma mark - UITableViewDataSource

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { /* ... */ }

#pragma mark - ZOCSuperclass

// ... 重載來(lái)自 ZOCSuperclass 的方法

#pragma mark - NSObject

- (NSString *)description { /* ... */ }

上面的標(biāo)記能明顯分離和組織代碼。你還可以用 cmd+Click 來(lái)快速跳轉(zhuǎn)到符號(hào)定義地方揩尸。 但是小心蛹屿,即使 paragma mark 是一門(mén)手藝,但是它不是讓你類(lèi)里面方法數(shù)量增加的一個(gè)理由:類(lèi)里面有太多方法說(shuō)明類(lèi)做了太多事情疲酌,需要考慮重構(gòu)了蜡峰。

關(guān)于 pragma

http://raptureinvenice.com/pragmas-arent-just-for-marks/ 有很好的關(guān)于 pragma 的討論了,在這邊我們?cè)僮霾糠终f(shuō)明朗恳。

大多數(shù) iOS 開(kāi)發(fā)者平時(shí)并沒(méi)有和很多編譯器選項(xiàng)打交道湿颅。一些選項(xiàng)是對(duì)控制嚴(yán)格檢查(或者不檢查)你的代碼或者錯(cuò)誤的。有時(shí)候粥诫,你想要用 pragma 直接產(chǎn)生一個(gè)異常油航,臨時(shí)打斷編譯器的行為。

當(dāng)你使用ARC的時(shí)候怀浆,編譯器幫你插入了內(nèi)存管理相關(guān)的調(diào)用谊囚。但是這樣可能產(chǎn)生一些煩人的事情。比如你使用 NSSelectorFromString來(lái)動(dòng)態(tài)地產(chǎn)生一個(gè) selector調(diào)用的時(shí)候执赡,ARC不知道這個(gè)方法是哪個(gè)并且不知道應(yīng)該用那種內(nèi)存管理方法镰踏,你會(huì)被提示performSelector may cause a leak because its selector is unknown(執(zhí)行 selector 可能導(dǎo)致泄漏,因?yàn)檫@個(gè) selector 是未知的).

如果你知道你的代碼不會(huì)導(dǎo)致內(nèi)存泄露沙合,你可以通過(guò)加入這些代碼忽略這些警告

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

[myObj performSelector:mySelector withObject:name];

#pragma clang diagnostic pop

注意我們是如何在相關(guān)代碼上下文中用 pragma停用-Warc-performSelector-leaks 檢查的奠伪。這確保我們沒(méi)有全局禁用。如果全局禁用首懈,可能會(huì)導(dǎo)致錯(cuò)誤绊率。

全部的選項(xiàng)可以在 The Clang User's Manual 找到并且學(xué)習(xí)。

忽略沒(méi)用使用變量的編譯警告

告訴你申明的變量它將不會(huì)被使用究履,這種做法很有用滤否。大多數(shù)情況下,你希望移除這些引用來(lái)(稍微地)提高性能最仑,但是有時(shí)候你希望保留它們藐俺。為什么炊甲?或許它們以后有用,或者有些特性只是暫時(shí)移除欲芹。無(wú)論如何蜜葱,一個(gè)消除這些警告的好方法是用相關(guān)語(yǔ)句進(jìn)行注解,使用 #pragma unused():

- (NSInteger)giveMeFive
{
    NSString *foo;
    #pragma unused (foo)

    return 5;
}

現(xiàn)在你的代碼不用任何編譯警告了耀石。注意你的 pragma 需要標(biāo)記到問(wèn)題代碼之下。

明確編譯器警告和錯(cuò)誤

編譯器是一個(gè)機(jī)器人爸黄,它會(huì)標(biāo)記你代碼中被 Clang 規(guī)則定義為錯(cuò)誤的地方滞伟。但是,你總是比 Clang 更聰明炕贵。通常梆奈,你會(huì)發(fā)現(xiàn)一些討厭的代碼會(huì)導(dǎo)致這個(gè)問(wèn)題,但是暫時(shí)卻解決不了称开。你可以這樣明確一個(gè)錯(cuò)誤:

- (NSInteger)divide:(NSInteger)dividend by:(NSInteger)divisor
{
    #error Whoa, buddy, you need to check for zero here!
    return (dividend / divisor);
}

類(lèi)似的亩钟,你可以這樣標(biāo)明一個(gè)警告

- (float)divide:(float)dividend by:(float)divisor
{
    #warning Dude, don't compare floating point numbers like this!
    if (divisor != 0.0) {
        return (dividend / divisor);
    }
    else {
        return NAN;
    }
}

字符串文檔

所有重要的方法,接口鳖轰,分類(lèi)以及協(xié)議定義應(yīng)該有伴隨的注釋來(lái)解釋它們的用途以及如何使用清酥。更多的例子可以看 Google 代碼風(fēng)格指南中的 File and Declaration Comments。

簡(jiǎn)而言之:有長(zhǎng)的和短的兩種字符串文檔蕴侣。

短文檔適用于單行的文件焰轻,包括注釋斜杠。它適合簡(jiǎn)短的函數(shù)昆雀,特別是(但不僅僅是)非 public 的 API:

// Return a user-readable form of a Frobnozz, html-escaped.
文本應(yīng)該用一個(gè)動(dòng)詞 ("return") 而不是 "returns" 這樣的描述辱志。

如果描述超過(guò)一行,應(yīng)改用長(zhǎng)字符串文檔:

/**開(kāi)始
換行寫(xiě)一句總結(jié)的話(huà)狞膘,以?或者!或者.結(jié)尾揩懒。
空一行
在與第一行對(duì)齊的位置開(kāi)始寫(xiě)剩下的注釋
最后用*/結(jié)束。

/**
 This comment serves to demonstrate the format of a docstring.

 Note that the summary line is always at most one line long, and
 after the opening block comment, and each line of text is preceded
 by a single space.
*/

一個(gè)函數(shù)必須有一個(gè)字符串文檔挽封,除非它符合下面的所有條件:

  • 非公開(kāi)
  • 很短
  • 顯而易見(jiàn)
    字符串文檔應(yīng)該描述函數(shù)的調(diào)用符號(hào)和語(yǔ)義已球,而不是它如何實(shí)現(xiàn)。

注釋

當(dāng)它需要的時(shí)候场仲,注釋?xiě)?yīng)該用來(lái)解釋特定的代碼做了什么和悦。所有的注釋必須被持續(xù)維護(hù)或者干脆就刪掉。

塊注釋?xiě)?yīng)該被避免渠缕,代碼本身應(yīng)該盡可能就像文檔一樣表示意圖鸽素,只需要很少的打斷注釋。 例外: 這不能適用于用來(lái)產(chǎn)生文檔的注釋

頭文檔

一個(gè)類(lèi)的文檔應(yīng)該只在.h文件里用 Doxygen/AppleDoc的語(yǔ)法書(shū)寫(xiě)亦鳞。 方法和屬性都應(yīng)該提供文檔馍忽。

**例子: **

/**
 *  Designated initializer.
 *
 *  @param  store  The store for CRUD operations.
 *  @param  searchService The search service used to query the store.
 *
 *  @return A ZOCCRUDOperationsStore object.
 */
- (instancetype)initWithOperationsStore:(id<ZOCGenericStoreProtocol>)store
                          searchService:(id<ZOCGenericSearchServiceProtocol>)searchService;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末棒坏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子遭笋,更是在濱河造成了極大的恐慌坝冕,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓦呼,死亡現(xiàn)場(chǎng)離奇詭異喂窟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)央串,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)磨澡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人质和,你說(shuō)我怎么就攤上這事稳摄。” “怎么了饲宿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵厦酬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我瘫想,道長(zhǎng)仗阅,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任国夜,我火速辦了婚禮霹菊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘支竹。我一直安慰自己旋廷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布礼搁。 她就那樣靜靜地躺著饶碘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪馒吴。 梳的紋絲不亂的頭發(fā)上扎运,一...
    開(kāi)封第一講書(shū)人閱讀 49,785評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音饮戳,去河邊找鬼豪治。 笑死,一個(gè)胖子當(dāng)著我的面吹牛扯罐,可吹牛的內(nèi)容都是我干的负拟。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼歹河,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼掩浙!你這毒婦竟也來(lái)了花吟?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤厨姚,失蹤者是張志新(化名)和其女友劉穎衅澈,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谬墙,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡今布,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拭抬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片险耀。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖玖喘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蘑志,我是刑警寧澤累奈,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站急但,受9級(jí)特大地震影響澎媒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜波桩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一戒努、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧镐躲,春花似錦储玫、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至裆熙,卻和暖如春端礼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背入录。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工蛤奥, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人僚稿。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓凡桥,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蚀同。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唬血,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

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