iOS編程規(guī)范0規(guī)范
0.1前言
為??高產(chǎn)品代碼質(zhì)量,指導(dǎo)廣大軟件開發(fā)人員編寫出簡潔、可維護(hù)、可靠、可
測試、高效 、 可移植的代碼,編程規(guī)范修訂工作組分析 、總結(jié)了我司的各
種典型編碼問題,并參考了業(yè)界編程規(guī) 范近年來的成果,重新對我司1999年
版編程規(guī)范進(jìn)行了梳理、優(yōu)化、刷新,編寫了本規(guī)范。 本規(guī)范將分為完整版
和精簡版,完整版將包括更多的樣例 、規(guī)范的解釋以及參考材料(what &
why),而精簡版將只包含規(guī)則部分(what)以便查閱。在本規(guī)范的最后,列出了
一些業(yè)界比較優(yōu)秀的編程規(guī)范,作為延伸閱讀參考材料。
0.2代碼總體原則
1、清晰第一??清晰性是易于維護(hù) 、易于重構(gòu)的程序必需具備的特征 。代碼首
先是給人讀的,好的代碼應(yīng)當(dāng)
可以像文章一樣發(fā)聲朗誦出來。??目前軟件維護(hù)期成本占整個生命周期成本的
40%~90%。根據(jù)業(yè)界經(jīng)驗(yàn),維護(hù)期變更代碼的成
本,小型系統(tǒng)是開發(fā)期的5倍,大型系統(tǒng)( 100萬行代碼以上)可以達(dá)到100倍。
業(yè)界的調(diào)查指出,開發(fā)組平均大約一半的人力用于彌補(bǔ)過去的錯誤,而不是添
加新的功能來幫助公司??高競爭力。
“程序必須為閱讀它的人而編寫,只是順便用于機(jī)器執(zhí)行。”——HaroldAbelson和Gerald Jay Sussman
“編寫程序應(yīng)該以人為本,計(jì)算機(jī)第二。”——Steve McConnell
本規(guī)范通過后文中的原則(如頭優(yōu)秀的代碼可以自我解釋,不通過注釋即可輕
易讀懂/頭文 件中適合放置接口的聲明,不適合放置實(shí)現(xiàn)/除了常見的通用
縮寫以外,不使用單詞縮寫,不得使 用漢語拼音)、規(guī)則(如防止局部變量與全
局變量同名)等說明清晰的重要性。
一般情況下,代碼的可閱讀性高于性能,只有確定性能是瓶頸時,才應(yīng)該主動優(yōu)
化。2、簡潔為美
簡潔就是易于理解并且易于實(shí)現(xiàn)。代碼越長越難以看懂,也就越容易在修改時
引入錯誤 。寫 的代碼越多,意味著出錯的地方越多,也就意味著代碼的可靠
性越低 。因此,我們??倡大家通過編 寫簡潔明了的代碼來??升代碼可靠性。
廢棄的代碼(沒有被調(diào)用的函數(shù)和全局變量)要及時清除,重復(fù)代碼應(yīng)該盡可
能??煉成函數(shù) 。3、選擇合適的風(fēng)格,與代碼原有風(fēng)格保持一致
產(chǎn)品所有人共同分享同一種風(fēng)格所帶來的好處,遠(yuǎn)遠(yuǎn)超出為了統(tǒng)一而付出的
代價 。在公司已 有編碼規(guī)范的指導(dǎo)下,審慎地編排代碼以使代碼盡可能清晰,是一項(xiàng)非常重要的技能。如果重構(gòu)/修改其他風(fēng)格的代碼時,比較明智的做法
是根據(jù)現(xiàn)有代碼的現(xiàn)有風(fēng)格繼續(xù)編寫代碼 。
0.3規(guī)范實(shí)施、解釋
本規(guī)范制定了編寫iOS程序的基本原則、規(guī)則和建議。??本規(guī)范適用于公司內(nèi)
所有iOS軟件。本規(guī)范自發(fā)布之日起生效,對以后新編寫的和修改的代碼應(yīng)遵
守本規(guī)范。??本規(guī)范由質(zhì)量體系發(fā)布和維護(hù)。實(shí)施中遇到問題,可以 在組內(nèi)??
出。 個體程序員不得違反本規(guī)范中的相關(guān)規(guī)則。
0.4術(shù)語定義
原則:編程時必須堅(jiān)持的指導(dǎo)思想。
規(guī)則:編程時強(qiáng)制必須遵守的約定。
建議:編程時必須加以考慮的約定。??說明:對此原則/規(guī)則/建議進(jìn)行必要的解釋。
示例:對此原則/規(guī)則/建議從正、反兩個方面給出例子。 延伸閱讀材料:建議
進(jìn)一步閱讀的參考材料。
1.Cocoa和Objective-c特性頭文件引用
1.1規(guī)則:#import引用Objective-C/Objective-C++頭文件; #include引用C/C++頭文件1.2規(guī)則:使用#include時要注意#define頭保護(hù)。
1.3建議:#import頭文件按模塊分類。
說明:對頭文件按模塊分類,使代碼易讀,也便于理解。 示例:
// Three20UINavigator??#import "Three20UINavigator/TTURLNavigatorPattern.h"
#import "Three20UINavigator/TTURLGeneratorPattern.h"
// Core??#import "Three20Core/TTGlobalCore.h"??#import
"Three20Core/TTCorePreprocessorMacros.h"
1.4建議:#import的順序,應(yīng)該是先引用自定義類,再引用系統(tǒng)類/框架。
說明:將系統(tǒng)類放在最后引入,可避免和檢驗(yàn)自定義類的頭文件引用不完整 漏
洞。 示例:
#import
// UINavigator??#import "Three20UINavigator/TTURLNavigatorPattern.h"
`Three20UINavigator/TTURLNavigatorPattern.h`依賴于Foundation.h ,但其自
身并沒有
import Foundation .h。如果該類僅僅在此處被使用,那么工程可以順利編譯。但
是,我們單獨(dú)import Three20UINavigator/TTURLNavigatorPattern.h ,編譯時就
會報錯。
1.5建議:#import根框架而不是單獨(dú)的零散文件
說明:當(dāng)你試圖從框架(如Cocoa或者Foundation)中包含若干零散的系統(tǒng)頭
文件時,實(shí)際上包 含頂層根框架的話,編譯器要做的工作更少。根框架通常已
經(jīng)經(jīng)過預(yù)編譯,加載更快。??示例:
良好的風(fēng)格:??#import 不良好的風(fēng)格:??#import
#import
1.6建議:@class與#import
說明:如需要繼承類或執(zhí)行協(xié)議,可以在.h中進(jìn)行#import類或協(xié)議;其他情況下,在.h中聲明用@classs聲明此類即可。這樣可以減少因頭文件依賴引起重復(fù)編
譯,??高編譯速度。
常量&變量
1.7規(guī)則:init和dealloc內(nèi)避免使用訪問器
說明:在init和dealloc方法執(zhí)行的過程中,子類可能會處在一個不一致的狀
態(tài),所以這些方 法中的代碼應(yīng)避免調(diào)用訪問器。??子類尚未初始化,或在init和dealloc方法執(zhí)行時已經(jīng)被銷毀,會使訪問器方法很可能不可靠。 實(shí)際上,應(yīng)在
這些方法中直接對 內(nèi)部成員變量進(jìn)行賦值或釋放操作。
示例:
正確:-??(id)init{
self = [super init]; if (self) {
bar_ = [[NSMutableString alloc] init]; // good }
return self; }
- (void)dealloc { [bar_ release]; [super dealloc];
}錯??誤:-??(id)init {
self = [super init]; if (self) {
// good
self.bar = [NSMutableString string]; // avoid }
return self; }
- (void)dealloc { self.bar = nil; [super dealloc];
// avoid
}
1.8規(guī)則:禁止對屬性做出錯誤的內(nèi)部成員變量聲明
說明: xcode4.4開始會自動@synthesize ,為@ property聲明一個前綴下劃線
的內(nèi)部成員變量。因 此,不需要為屬性重復(fù)做出內(nèi)部成員變量聲明。同時,禁
止 對屬性做出錯誤的內(nèi)部成員變量聲明 。 示例-1:
良好的風(fēng)格:??@interface MyClass : NSObject {
}??@property(copy, nonatomic) NSString *name; @end??錯誤的聲明:??@interface
MyClass : NSObject {
NSString *name;
}??@property(copy, nonatomic) NSString *name; @end??------------范例-2:??@interface t1 : NSObject
{??NSString *a;
}??@property (nonatomic,retain) NSString *a; -(BOOL)isStringEmpty;
@end
warning:Autosynthesized property 'a' will use synthesized instance variable '_a',
not existing instance variable 'a'
#import "t1.h"
@implementation t1 -(id)init??{
if ( self = [super init] ) {
a = @"a"; }
return self; }
-(BOOL)isStringEmpty {
NSLog(@"_a=%@ a=%@ self.a=%@",_a,a,self.a);
return [a isEqualToString:@""]; }
@end
===========??2014-04-09 15:23:25.837 iOS規(guī)范sample[5451:70b] _a=(null) a=a
self.a=(null)
1.9建議:使用常類型變量,而不是內(nèi)嵌的字符串字面值或數(shù)字
說明:常類型變量便于復(fù)用常用的變量值(如π),同時可以快速地修改值而無
需查找替換。 示例:良好的風(fēng)格:
static NSString * const RNCAboutViewControllerCompanyName = @"The
NewYork Times Company";
static const CGFloat RNCImageThumbnailHeight = 50.0;不良好的風(fēng)格:??#define
CompanyName @"The New York Times Company" #define thumbnailHeight 2
1.10建議:不用在init方法中,將成員變量初始化為0或者nil
說明:剛分配的對象,默認(rèn)值都是0,除了isa指針(譯者注: NSObject的isa識對象的類型)。所以不用在初始化器里面寫一堆將成員初始化為0或者nil的代碼。
1.11建議:按實(shí)際需要來定義成員變量的作用域
說明: 1.如果只是單純的private變量,最好聲明在interface里。??2.如果是類的public屬性,就用property寫在.h文件里。??3.如果自己內(nèi)部需要setter和getter來實(shí)現(xiàn)一些東西,就在.m文件的類目里用property
來聲明。 不要將私有的實(shí)例變量和方法聲明在頭文件中,應(yīng)將私有變量和方
法聲明在實(shí)現(xiàn)文件的類擴(kuò)展內(nèi) 。 示例:
不良的風(fēng)格:??//MyViewController.h文件??@interface MyViewController :
UIViewController
UITableViewDelegate> { @private:
UITableView *_myTableView; //私有實(shí)例變量}
@property (nonatomic,strong) NSNumber *variableUsedInternally;//內(nèi)部使用
的屬性- (void)sortName; //只用于內(nèi)部使用的方法??@end??良好的風(fēng)格:
//MyViewController.m文件使用類擴(kuò)展??@interface
MyViewController() {
UITableView *_myTableView;??//外部需要訪問的實(shí)例變量聲明為屬性,不需要
外部訪問的聲明為實(shí)例變量
NSNumber * variableUsedInternally; }
@end
1.12建議:字符串應(yīng)使用copy屬性(Attribute)
說明:應(yīng)該用copy屬性(attribute)聲明NSString屬性(property)。 從邏輯上,確保遵守NSString的setter必須使用copy而不是retain的原則。
1.13建議:謹(jǐn)慎聲明屬性的原子性
說明:一定要注意屬性(property)的開銷。缺省情況下,所有synthesize的setter和getter都是原子的。這會給每個get或者set帶來一定的同步開銷。將屬
性( property )聲明為nonatomic,除非你需要原子性。
1.14建議:點(diǎn)引用只用于簡單的屬性set、get操作
說明:點(diǎn)引用只用于簡單的屬性set、get操作,但不應(yīng)該用它來調(diào)用對象的其
它操作。 示例:
正確的做法:??NSString *oldName = myObject.name; myObject.name = @"Alice";
錯誤的做法:??NSArray *array = [[NSArray arrayWithObject:@"hello"] retain];
NSUInteger numberOfItems = array.count; // not a property array.release; // not a
property
1.15建議:autorelease優(yōu)先retain其次(非ARC)
說明:當(dāng)給一個變量賦值新的對象時,必須先釋放掉舊的對象以避免內(nèi)存泄露。
有很多“正確的”方法可以處理這種情況。我們則選擇“autorelease之后retain”的方法,因?yàn)槭聦?shí)證明它不 容易出錯。注意大的循環(huán)會填滿autorelease池,并且可能效率上會差一點(diǎn),但權(quán)衡之下我們認(rèn)為是可以接受的。
示例:
- (void)setFoo:(GMFoo *)aFoo {??[foo_ autorelease]; // Won't dealloc if |foo_| ==
|aFoo| foo_ = [aFoo retain];
}
1.16建議:使用nil來檢查應(yīng)用程序的邏輯流程,而不是避免崩潰
說明:Objective-C運(yùn)行時會處理向nil對象發(fā)送消息的情況。如果方法沒有返
回值,就沒關(guān)系。 如果有返回值,可能由于運(yùn)行時架構(gòu)、返回值類型以及OS X版本的不同而不同,參見Apple’s documentation。??注意,這和C/C++中檢查指
針是否為’NULL’很不一樣,C/C++運(yùn)行時不做任何檢查,從而導(dǎo)致 應(yīng)用程序
崩潰。因此你仍然需要保證你不會對一個C/C++的空指針解引用。
1.17建議:BOOL的陷阱,不要直接將BOOL值與YES進(jìn)行比較
說明:Ojbective-C中把BOOL定義成無符號字符型,這意味著BOOL類型
的值遠(yuǎn)不止YES(1)或
NO(0),所以,不要直接將BOOL值與YES進(jìn)行比較。
示例-1:??BOOL a = 2.5;
if (a == YES) {
NSLog(@"a == yes"); }
else if(a == NO){
NSLog(@"a == no"); }
else
{??NSLog(@"a == other");
}??NSLog(@"a+0.5 = %f",a+0.5);iOS編程規(guī)范v1.0
==========??2014-04-07 21:56:14.280 2014-04-07 21:56:14.281示例-2:??BOOL a =130;
if (a == YES) {
NSLog(@"a == yes"); }
else if(a == NO){
NSLog(@"a == no"); }
else
{??NSLog(@"a == other");
test[1224:907] a == other test[1224:907] a+0.5 = 2.500000
}??NSLog(@"a=%hhd a+0.5 = %f",a,a+0.5);??==========??2014-04-07 22:14:07.986
test[1510:907] a == other??2014-04-07 22:14:07.988 test[1510:907] a=-126 a+0.5 =
-125.500000
1.18建議:BOOL的陷阱,不要直接把整形轉(zhuǎn)換成BOOL
說明:Ojbective-C中把BOOL定義成無符號字符型,不要直接把整形轉(zhuǎn)換成BOOL。常見的錯誤 包括將數(shù)組的大小、指針值及位運(yùn)算的結(jié)果直接轉(zhuǎn)換成BOOL ,取決于整型結(jié)果的最后一個字節(jié),很可能會產(chǎn)生一個NO值。當(dāng)轉(zhuǎn)
換整形至BOOL時,使用三目操作符來返回YES或者NO。(譯者 注:讀者
可以試一下任意的256的整數(shù)的轉(zhuǎn)換結(jié)果,如256、512 ...)
示例:錯??誤的用法:
- (BOOL)isBold {??return [self fontTraits] & NSFontBoldTrait;}
- (BOOL)isValid {??return [self stringValue];
}
正確的用法:??? (BOOL)isBold { return ([self fontTraits] & NSFontBoldTrait) ?
YES : NO;
} - (BOOL)isValid {??return [self stringValue] != nil;??} - (BOOL)isEnabled {??return
[self isValid] && [self isBold]; }
1.19建議:盡量使用NSInteger,而不是int
說明:當(dāng)需要使用int類型的變量的時候,可以像寫C的程序一樣,用int,也可以
用NSInteger,但 更推薦使用NSInteger,因?yàn)檫@樣就不用考慮設(shè)備是32位的還
是64位的.
1.20點(diǎn)標(biāo)記語法
說明:屬性和冪等方法(多次調(diào)用和一次調(diào)用返回的結(jié)果相同)使用點(diǎn)標(biāo)記語法
訪問,其他的情況 使用方括號標(biāo)記語法。??示例:
良好的風(fēng)格:??view.backgroundColor = [UIColor orangeColor]; [UIApplication
sharedApplication].delegate;不良的風(fēng)格:??[view setBackgroundColor:[UIColor
orangeColor]]; UIApplication.sharedApplication.delegate;
類和方法
1.21規(guī)則:當(dāng)子類需要使用init函數(shù)時,確保已經(jīng)重載了父類的構(gòu)造函數(shù)。
說明:當(dāng)子類需要使用init函數(shù)時,確保已經(jīng)重載了父類的構(gòu)造函數(shù) 。否則,子類
的初始化不會調(diào) 用,這會導(dǎo)致很多很難定位的bug。
1.22規(guī)則:出參與入?yún)⑿鑼?yīng)
說明:在32位系統(tǒng)中,int和long都是32位的,但是在64位系統(tǒng)中,long則是64位的。
將long賦值給int,在64位系統(tǒng)中,會出現(xiàn)truncate的隱患。??示例:
實(shí)參與形參類型不一致
返回與定義返回類型不一致
返回與接受參數(shù)類型不一致。
long PerformCalculation(void);??int x = PerformCalculation(); // incorrect long y =
PerformCalculation(); // correct!
1.23建議:明確指定構(gòu)造函數(shù)
說明:對于需要繼承你的類的人來說,明確指定構(gòu)造函數(shù)十分重要 。這樣他們
就可以只重寫一個構(gòu) 造函數(shù)(可能是幾個)來保證他們的子類的構(gòu)造函數(shù)會被
調(diào)用 。這也有助于將來別人調(diào)試你的類時,理解初始化代碼的工作流程。
1.24建議:避免重載+new
說明:不要調(diào)用NSObject的類方法new,或在子類中重載new方法。使用new方
法會使關(guān)于內(nèi)存分配 的代碼審核變得很困難。使用alloc和init來創(chuàng)建并初始
化對象。
1.25建議:保持公共API簡單
說明:保持類簡單;避免“廚房水槽( kitchen-sink)”式的API。如果一個函數(shù)壓
根沒必要公開,就不要這么做。用私有類別保證公共頭文件整潔。??與C++不
同, Objective-C沒有方法來區(qū)分公共的方法和私有的方法–所有的方法都
是公共的(譯者注:這取決于Objective-C運(yùn)行時的方法調(diào)用的消息機(jī)制)。因
此,除非客戶端的代碼期望 使用某個方法,不要把這個方法放進(jìn)公共API中。
盡可能的避免了你不希望被調(diào)用的方法卻被調(diào) 用到。這包括重載父類的方
法 。對于內(nèi)部實(shí)現(xiàn)所需要的方法,在實(shí)現(xiàn)的文件中定義一個類別,而不 是把
它們放進(jìn)公有的頭文件中。
示例:??// GTMFoo.m
#import "GTMFoo.h"
@interface GTMFoo (PrivateDelegateHandling)??- (NSString
*)doSomethingWithDelegate; // Declare private method @end
@implementation GTMFoo(PrivateDelegateHandling) - (NSString
*)doSomethingWithDelegate {
// Implement this method }
@end
1.26建議:大的@implementation用categories拆分成更容易理解的小塊。
說明:便于理解的同時,還可以為最適合的類添加新的、特定應(yīng)用程序的功能。
例如,當(dāng)添加一個“middle truncation”方法時,創(chuàng)建一個NSString的新類別并
把方法放在里面,要比創(chuàng)建任意 的一個新類把方法放進(jìn)里面好得多。
宏
1.27規(guī)則:用宏定義表達(dá)式時,要使用完備的括號。
示例:如??下定義的宏都存在一定的風(fēng)險。#define RECTANGLE_AREA( a, b )
#define RECTANGLE_AREA( a, b ) #define RECTANGLE_AREA( a, b )正確
的定義應(yīng)為:??#define RECTANGLE_AREA( a, b )
a * b??(a * b) (a) * (b)
((a) * (b))
1.28規(guī)則:將宏所定義的多條表達(dá)式放在大括號中。
示例:下??面的語句只有宏的第一條表達(dá)式被執(zhí)行。為了說明問題, for語句的書
寫稍 不符規(guī)范。
#define INTI_RECT_VALUE( a, b )\??a = 0;\??b = 0;??for (index = 0; index <
RECT_TOTAL_NUM; index++) INTI_RECT_VALUE( rect.a, rect.b );正確的
用法應(yīng)為:
#define INTI_RECT_VALUE( a, b )\ {\??a = 0;\??b = 0;\}
1.29規(guī)則:使用宏時,不允許參數(shù)發(fā)生變化。
示例:如下用法可能導(dǎo)致錯誤。
#define SQUARE( a ) ((a) * (a))??int a = 5;??int b;??b = SQUARE( a++ ); //結(jié)果:a = 7,即執(zhí)行了兩次增1。 正確的用法是:
b = SQUARE( a );??a++; //結(jié)果:a = 6,即只執(zhí)行了一次增1。其他
1.30建議:委托模式
說明:委托對象不應(yīng)該被retain實(shí)??現(xiàn)委托模式的類應(yīng):??1.擁有一個名為_delegate的實(shí)例變量來引用委托。2.因此,訪問器方法應(yīng)該命名為delegate和setDelegate:。3._delegate對象不應(yīng)該被retain。
1.31建議:模型/視圖/控制器(MVC)說明:分離模型與視圖。分離控制器與視圖、模型。???分離模型與視圖:不要假
設(shè)模型或者數(shù)據(jù)源的表示方法 。保持?jǐn)?shù)據(jù)源與表示層之間的接口抽
象。視圖不需要了解模型的邏輯(主要的規(guī)則是問問你自己,對于數(shù)據(jù)源的一個
實(shí)例,
有沒有可能有多種不同狀態(tài)的表示方法)。???分離控制器與模型、視圖:不要
把所有的“業(yè)務(wù)邏輯”放進(jìn)跟視圖有關(guān)的類中。這使代碼
非常難以復(fù)用 。使用控制器類來處理這些代碼,但保證控制器不需要了解太
多表示層的 邏輯。
1.32建議:應(yīng)該使用線程安全的模式創(chuàng)建共享的單例實(shí)例示例:??+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init]; });
return sharedInstance; }
1.33建議:盡量使用不透明視圖
說明:不透明的視圖可以極大地??高渲染的速度。因此如非必要,可以將table
cell及其子視圖的opaque屬性設(shè)為YES(默認(rèn)值)。
1.34建議:做條件判斷時,應(yīng)使用Golden Path模式
說明:The goal here is to make the code on the left margin to be the “expected”
code execution path and the code that is indented to be the exception. Consistency
in this area is important to code readability.示??例:
良好的風(fēng)格:-??(void)someMethod{
if (![someOther boolValue]) return;
//Do something important }
不良好的風(fēng)格:-??(void)someMethod{
if ([someOther boolValue]) { //Do something important}}
================================良好的風(fēng)格:-??(void)someMethod??{if ([someOther boolValue]) { //Do something important return;
}
//Do something else important }
不良好的風(fēng)格:-??(void)someMethod{
if ([someOther boolValue]) { //Do something important
} else {??//Do something else important
}}
================================例外:-??(void)someMethod
{??if ([someOther boolValue]) {
//Do something important } else {
//Do something else important }
//Do this no matter what }
1.35建議:異常和錯誤處理
不要在流控制語句中使用異常( NSException )。??異常僅用于表明程序員的錯
誤。??為了表明一個錯誤,使用NSError *。 當(dāng)一個方法通過引用返回一個錯
誤參數(shù),應(yīng)該檢測返回值的狀態(tài),而不是錯誤參數(shù)的狀態(tài)。 良好的風(fēng)格:
NSError *error;??if (![self trySomethingWithError:&error]) {
// Handle Error }
不良的風(fēng)格:??NSError *error;??[self trySomethingWithError:&error]; if (error) {
// Handle Error }
在方法執(zhí)行成功的情況下賦值非 潰)。
1.36建議:三元運(yùn)算符
Null值給錯誤參數(shù),會使路徑跳轉(zhuǎn)到假條件分支(隨后程序奔
說明:長的三元運(yùn)算符應(yīng)使用圓括號括起來。三元運(yùn)算符僅用于賦值和做參數(shù)。Blah *a = (stuff == thing ? foo : bar);
合并的nil三元運(yùn)算符應(yīng)該盡量避免。 示例:
不良的風(fēng)格:??Blah *b = thingThatCouldBeNil ?: defaultValue;多分支條件應(yīng)該
使用if語句或重構(gòu)為實(shí)例變量。 良好的風(fēng)格:??result = a > b ? x : y;不??良的風(fēng)
格:??result = a > b ? x = c > d ? c : d : y;
2.命名
2.1建議:關(guān)于命名和命名風(fēng)格
說明:對于易維護(hù)的代碼而言,命名規(guī)則非常重要。Objective-C的方法名往往
十分長,但代碼塊 讀起來就像散文一樣,不需要太多的代碼注釋。
當(dāng)編寫純粹的Objective-C代碼時,我們基本遵守標(biāo)準(zhǔn)的Objective-C naming
rules,這 些命名規(guī)則可能與C++風(fēng)格指南中的大相徑庭。例如, Google的C++風(fēng)格指南中推薦使用下劃線分隔的單詞作為變量名,而(蘋果的)風(fēng)格指
南則使用駝峰命名法,這在Objective-C社區(qū)中非 常普遍。
命名可適當(dāng)使用縮略詞。但必須確保,這些縮略詞是久經(jīng)歷史,認(rèn)識性比較高
的縮略詞。如 下:縮略詞。不要使用,你自己認(rèn)為大家可能會理解的縮略詞 。
因?yàn)?跳出語言環(huán)境之后,這個縮 略詞就變得難懂了。
當(dāng)編寫Objective-C++代碼時,事情就不這么簡單了。許多項(xiàng)目需要實(shí)現(xiàn)跨平
臺的C++ API,并混合一些Objective-C、Cocoa代碼,或者直接以C++為后
端,前端用本地Cocoa代碼。 這就導(dǎo)致了兩種命名方式直接不統(tǒng)一。我們的
解決方案是:編碼風(fēng)格取決于方法/函數(shù)以哪種語言 實(shí)現(xiàn)。如果在一個@implementation語句中,就使用Objective-C的風(fēng)格。如果實(shí)現(xiàn)一個C++的
類,就使用C++的風(fēng)格。這樣避免了一個函數(shù)里面實(shí)例變量和局部變量命名
規(guī)則混亂,嚴(yán)重影響 可讀性。
2.2建議:命名盡量簡潔,但不能因?yàn)楹啙嵍姑y以理解
示例:
Code
insertObject: atIndex: insert:at: removeObjectAtIndex: removeObject:remove:??In general, don’t abbreviate names of things.
Code
destinationSelection
destSel
setBackgroundColor:
setBkgdColor:
常量和變量
2.3建議:關(guān)于變量名
Commentary
Good.??Not clear; what is being inserted? what does “at” signify???Good.??Good,
because it removes object referred to in argument.??Not clear; what is being
removed?
Spell them out, even if they’re long:
Commentary
Good.
Not clear.
Good.
Not clear.
說明:變量名應(yīng)該以小寫字母開頭,并使用駝峰格式 。盡量為變量起一個??述
性的名字 。不要擔(dān)心 浪費(fèi)列寬,因?yàn)樽屝碌拇a閱讀者立即理解你的代碼更
重要。??示例:
錯誤的命名: int w;??int nerr;??int nCompConns;??tix = [[NSMutableArray alloc] init];
obj = [someObject object];
p = [network port];
正確的命名: int numErrors;??int numCompletedConnections;??tickets =
[[NSMutableArray alloc] init]; userInfo = [someObject object];
port = [network port];
2.4建議:實(shí)例變量
說明:實(shí)例變量應(yīng)該混合大小寫,并以下劃線作為 前綴,如_usernameTextField。
然而,如果不 能使用Objective-C 2.0(操作系統(tǒng)版本的限制),并且使用了KVO/KVC綁定成員變量時,我們允 許例外(譯者注: KVO=Key Value
Observing,KVC=Key Value Coding)。這種情況下,可以以一 個下劃線作為成員
變量名字的前綴,這是蘋果所接受的鍵/值命名慣例。如果可以使用
Objective-C 2.0,@property以及@synthesize??供了遵從這一命名規(guī)則的解
決方案。
2.5建議:常量
常量名(如宏定義、枚舉、靜態(tài)局部變量等)應(yīng)該以小寫字母k開頭,使用駝峰
格式分隔單詞,示例:
kInvalidHandle,kWritePerm。
2.6建議:不要使用單個字符來定義變量名。
說明:即時變量只是一個index,為它取名index,而不是i、j、k。 一般循環(huán)語句
的當(dāng)前對象的命名前綴包括“ one ”、“ a/an ”。對于簡單的單個對象使用“ item ”命名。??示例:
良好的風(fēng)格:??for (i = 0; i < count; i++) {
oneObject = [ allObjects objectAtIndex: i];
NSLog (@"oneObject: %@", oneObject); }
NSEnumerator *e = [allObjects objectEnumerator]; id item;??while ( item = [e
nextObject])
NSLog (@"item: %@", item);
2.7建議:對于NSString、NSArray、NSNumber或BOOL類型,變量的
命名一般不需要表明其 類型。
示例:良??好的風(fēng)格:
NSString NSMutableArray NSArray??BOOL不良的風(fēng)格: NSString
NSMutableArray NSArray
BOOL
*accountName;
*mailboxes;
*defaultHeaders;
userInputWasUpdated;
*accountName String ; *mailbox Array ; *defaultHeaders Array ;
userInputWasUpdated BOOL ;
如果變量不是以上基本常用類型,則變量的命名就應(yīng)該反映出自身的類型 。
但有時僅需要某 些類的一個實(shí)例的情況下,那么只需要基于類名進(jìn)行命名。NSImage *previewPaneImage ; NSProgressIndicator *upload
Indicator ;??NSFontManager * fontManager ; //基于類名命名
大部分情況下, NSArray或NSSet類型的變量只需要使用單詞復(fù)數(shù)形式(比
如??mailboxes ),不必在命名中包含“ mutable ”。如果復(fù)數(shù)變量不是NSArray或NSSet類型,則 需要指定其類型。
良好的風(fēng)格:??NSDictionary * keyed AccountNames; NSDictionary * message
Dictionary ; NSIndexSet * selectedMailboxes IndexSet ;
類和方法
2.8規(guī)則:不要使用下劃線前綴來聲明私有方法。 說明:蘋果保留這一風(fēng)格。2.9規(guī)則:方法的每個參數(shù)必須有參數(shù)聲明,盡可能對參數(shù)做出??述,不能為空
示例:-??(void)sendAction:(SEL)aSelectortoObject:(id)anObject
forAllCells:(BOOL)flag;
Right.
-??(void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag Wrong. ;
- (id)viewWithTag:(NSInteger)aTag; Right. - (id)taggedView:(int)aTag; Wrong.2.10建議:關(guān)于類名
說明:類名(以及類別、協(xié)議名)應(yīng)首字母大寫,并以駝峰格式分割單詞。應(yīng)用層
的代碼,應(yīng)該盡 量避免不必要的前綴 。為每個類都添加相同的前綴無助于可
讀性 。當(dāng)編寫的代碼期望在不同應(yīng)用程 序間復(fù)用時,應(yīng)使用前綴(如:
GTMSendMessage )。
2.11建議:關(guān)于類別名
說明:類別名應(yīng)該有兩三個字母的前綴以表示類別是項(xiàng)目的一部分或者該類
別是通用的 。類別名應(yīng) 該包含它所擴(kuò)展的類的名字。
比如我們要基于NSString創(chuàng)建一個用于解析的類別,我們將把類別放在一個
名為GTMNSString+Parsing.h的文件中。類別本身命名為GTMStringParsingAdditions (是的,我們 知道類別名和文件名不一樣,但是這個
文件中可能存在多個不同的與解析有關(guān)類別)。類別中的方 法應(yīng)該以gtm_myCategoryMethodOnAString:為前綴以避免命名沖突,因?yàn)镺bjective-C只有一 個名字空間 。如果代碼不會分享出去,也不會運(yùn)行在不同的地址空
間中,方法名字就不那么重要了 。
類名與包含類別名的括號之間,應(yīng)該以一個空格分隔。2.12建議:關(guān)于方法名
說明:??一個方法的命名首先??述返回什么,接著是什么情況下被返回 。方法
簽名中冒號的前面??
述傳入?yún)?shù)的類型。 以下類方法和實(shí)例方法命名的格式語法: [object/class
thing+ condition ]; [object/class thing+ input :input]; [object/class thing+
identifer :input];
方法名應(yīng)該以小寫字母開頭,并混合駝峰格式。每個具名參數(shù)也應(yīng)該以小寫字
母開頭。 方法名應(yīng)盡量讀起來就像句子,這表示你應(yīng)該選擇與方法名連在一
起讀起來通順的參數(shù)
名。(例如,convertPoint:fromRect:或replaceCharactersInRange:withString:)。詳
情參見Apple’s Guide to Naming Methods。??訪問器方法應(yīng)該與他們 要獲取的
成員變量的名字一樣,但不應(yīng)該以get作為前綴。例如:
- (id)getDelegate; // AVOID
- (id)delegate; // GOOD示例:
rate
newString
subarray
= [number float Value];??= [string decomposed String WithCanonicalMapping ]; =
[array sub array WithRange :segment];
= [path
= [string
= [array
string ByExpandingTildeInPath ];??string ByAppendingString :@"Extra Text"];
object AtIndex :3];
= [NSString
= [NSArray
string WithFormat :@"%f",1.5]; array WithObject :newString];
不良的風(fēng)格:-??sortInfo //是返回排序結(jié)果還是給info做排序-refreshTimer //返回一個用于刷新的定時器還是刷新定時器-update //更新什么,如何更新
良好的風(fēng)格:-??currentSortInfo // "current"清楚地修飾了名詞SortInfo
-refreshDefaultTimer // refresh是一個動詞。-updateMenuItemTitle //一個正在
發(fā)生的動作
這僅限于Objective-C的方法名。C++的方法與函數(shù)的命名規(guī)則應(yīng)該遵從C++風(fēng)格指南中 的規(guī)則。
2.13建議:關(guān)于方法的參數(shù)名
說明:方法參數(shù)名一般使用的前綴包括“ the ”、“ an ”、“ new ”。 示例:良好的風(fēng)格:-??(void)setTitle:(NSString*)aTitle;
Cocoa命名舉例:
realPath
fullString
object
//類方法??newString??newArray??良好的自定義方法命名風(fēng)格:??recipients = [email
recipients SortedByLastName ];??newEmail = [CDCEmail email
WithSubjectLine :@"Extra Text"]; emails = [mailbox messages
ReceivedAfterDate :yesterdayDate];
當(dāng)需要獲取對象值的另一種類型的時候,方法命名的格式語法如下: [object
adjective +thing];??[object adjective +thing+ condition ];??[object adjective +thing+
input :input];
良好的自定義方法命名風(fēng)格:??capitalized = [name capitalized String];
- (void) setName:??- (id) keyForOption:??- (NSArray *) emailsForMailbox:??-
(CDCEmail *) emailForRecipients: (NSArray *) theRecipients;
(NSString *) newName; (CDCOption *) anOption (CDCMailbox *) theMailbox;
2.14建議:方法的參數(shù)名不要使用“and”做鏈接。
說明:當(dāng)參數(shù)較多時,代碼會顯得冗余。有一個例外,當(dāng)參數(shù)??述的是兩個不同
的action時,可以 用“and”做鏈接。
2.15建議:框架類模塊中,在類名和常類型變量名前添加一個由三個大寫的字
母組成的前綴(如RNC )。
說明:由于Objective-C不支持名字空間,為了防止出現(xiàn)命名空間的沖突,在類
名和常類型變量 名前添加一個由三個大寫的字母組成的前綴(如RNC ),對于Core Data實(shí)體名則可以忽略此規(guī) 則。如果你子類化了標(biāo)準(zhǔn)的Cocoa類,將
前綴和父類名合并是一個很好的做法。如繼承UITableView的類可命名為RNCTableView。
其他
2.16建議:關(guān)于文件名
說明:文件名須反映出其實(shí)現(xiàn)了什么類–包括大小寫。遵循你所參與項(xiàng)目的
約定。 文件的擴(kuò)展名應(yīng)該如下:
類別的文件名應(yīng)該包含被擴(kuò)展的類名,如: GTMNSString+Utils.h或``GTMNSTextView+Autocomplete.h``。
2.17建議:關(guān)于Objective-C++
說明:源代碼文件內(nèi),Ojbective-C++代碼遵循你正在實(shí)現(xiàn)的函數(shù)/方法的風(fēng)格。??為了最小化Cocoa/Objective-C與C++之間命名風(fēng)格的沖突,根據(jù)待實(shí)現(xiàn)的
函數(shù)/方法選 擇編碼風(fēng)格。實(shí)現(xiàn)@implementation語句塊時,使用Objective-C的命名規(guī)則;如果實(shí)現(xiàn)一個C++
iOS編程規(guī)范v1.0
.h
C/C++/Objective-C的頭
文件
.m
Ojbective-C實(shí)現(xiàn)文件
.mm
Ojbective-C++的實(shí)現(xiàn)文
件
.cc
純C++的實(shí)現(xiàn)文件
.c
純C的實(shí)現(xiàn)文件
的類,就使用C++命名規(guī)則。 示例:??// file: cross_platform_header.hclass CrossPlatformAPI { public:
...
int DoSomethingPlatformSpecific(); private:
int an_instance_var_;
};
// file: mac_implementation.mm
// impl on each platform
#include "cross_platform_header.h"
// A typical Objective-C class, using Objective-C naming. @interface
MyDelegate : NSObject {
@private??int instanceVar_; CrossPlatformAPI* backEndObject_;
}-??(void)respondToSomething:(id)something;@end??@implementation
MyDelegate??- (void)respondToSomething:(id)something {
// bridge from Cocoa through our C++ backend??instanceVar_ =
backEndObject->DoSomethingPlatformSpecific(); NSString* tempString =
[NSString stringWithInt:instanceVar_]; NSLog(@"%@", tempString);
} @end
// The platform-specific implementation of the C++ class, using // C++ naming.??int
CrossPlatformAPI::DoSomethingPlatformSpecific() {
NSString* temp_string = [NSString stringWithInt:an_instance_var_];
NSLog(@"%@", temp_string);??return [temp_string intValue];
}
2.18建議:圖片資源的命名
說明:圖片的命名應(yīng)該保持一致,以圖片的用途??述作為圖片文件名 。文件名
的命名使用駝峰式大 小寫風(fēng)格,文件名后可跟隨一個自定義的類名或者是自
定義的屬性名(如果有屬性名)、也可以 再跟上顏色??述以及/或者位置、
圖片的最終狀態(tài)。??示例:
良好的風(fēng)格:
RefreshBarButtonItem / RefreshBarButtonItem@2x和
RefreshBarButtonItemSelected / RefreshBarButtonItemSelected@2x
ArticleNavigationBarWhite / ArticleNavigationBarWhite@2x和ArticleNavigationBarBlackSelected / ArticleNavigationBarBlackSelected@2x.
被用作相似用途的圖片應(yīng)該使用一個圖片文件夾進(jìn)行分開管理。
2.19建議:關(guān)于縮略詞1
說明:雖然方法命名不應(yīng)使用縮略詞,然而有些縮略詞在過去被反復(fù)的使用,所以使用這些縮略詞 能更好的的表達(dá)代碼的含義。下表列出了Cocoa可接
受的縮略詞。
縮略詞
含義和備注
alloc
分配,撥出
alt
輪流,交替
app
應(yīng)用程序。比如NSApp表示全局程序?qū)?/p>
象。
calc
計(jì)算
dealloc
銷毀、析構(gòu)
func
函數(shù)
horiz
水平的
iOS編程規(guī)范v1.0
info
信息
init
初始化
max
最大的
min
最小的
msg
消息
nib
Interface Builder文
檔
pboard
黏貼板(僅對常量)
rect
矩形
temp
臨時、暫時
vert
垂直的
以下是一些常用的首字母縮略詞ASCII??PDF??XML
HTML
URL
RTF
HTTP
TIFF
JPG
PNG
GIF
LZW
ROM
RGB
CMYK
MIDI
FTP
2.20建議:關(guān)于縮略詞2-前綴
說明:系統(tǒng)的常用類作實(shí)例變量聲明時加入后綴UIViewController:VC
UIImage:Img UIImageView:ImgView UIView:View??UILabel:Lbl??UIButton:Btn
UINavigationBar:NBar UIToolBar:TBar UISearchBar:SBar
UITextField:TextField UITextView:TextView NSArray:Array
NSMutableArray:MArray NSDictionary:Dict NSMutableDictionary:MDict
NSString:Str NSMutableString:MStr NSSet:Set NSMutableSet:MSet
3.注釋
3.1原則:文件/類/框架的注釋盡量完整。變量/方法的注釋盡量簡潔。
說明:盡管注釋很重要,但最好的代碼應(yīng)該自成文檔。 并且注釋的更新往往沒
有代碼更新及時 。與 其寫一段復(fù)雜的注釋,不如直接起一個有意義的名字 。
更新代碼時一定要更新注釋,防止對代碼造 成誤解。
3.2規(guī)則:文件注釋
說明:每個文件的開頭以文件內(nèi)容的簡要??述起始,緊接著是作者,最后是版
權(quán)聲明和 樣板。??版權(quán)信息及作者??每個文件應(yīng)該按順序包括如下項(xiàng):
/或許可證
?文件內(nèi)容的簡要??述???代碼作者???版權(quán)信息聲明(如:Copyright 2008 Google
Inc.)???必要的話,加上許可證樣板。為項(xiàng)目選擇一個合適的授權(quán)樣板(例如,
Apache 2.0, BSD, LGPL,
GPL)。??如果你對其他人的原始代碼作出重大的修改,請把你自己的名字添加
到作者里面 。當(dāng)另外一個代碼 貢獻(xiàn)者對文件有問題時,他需要知道怎么聯(lián)系
你,這十分有用。
3.3建議:使用javadoc-style注釋風(fēng)格。
說明:注釋的第一行是對注釋API的總結(jié),隨后的注釋行是對代碼更多細(xì)節(jié)的
解釋。 示例:
良好的風(fēng)格: /**
* The maximum size of a download that is allowed.??*??* If a response reports a
content length greater than the max * will be cancelled.
This is helpful for preventing excessive memory usage.??* Setting this to zero will
allow all downloads regardless of size. *??* @default 150000 bytes??*/
@property (nonatomic) NSUInteger maxContentLength;
3.4建議:聲明部分的注釋
說明:每個接口、類別以及協(xié)議應(yīng)輔以注釋,以??述它的目的及與整個項(xiàng)目的關(guān)
系。如果你已經(jīng)在文件頭部詳細(xì)??述了接口,可以直接說明“完整的??述請參
見文件頭部”,但是一定 要有這部分注釋。 另外,公共接口的每個方法,都應(yīng)該
有注釋來解釋它的作用、參數(shù)、返回值以及其它影響。 如果有的話,為類的
線程安全性作注釋。如果類的實(shí)例可以被多個線程訪問,記得注釋多線程條件
下的使用規(guī)則。
// A delegate for NSApplication to handle notifications about app // launch and
shutdown. Owned by the main app controller. @interface MyAppDelegate :
NSObject {
...
} @end
3.5建議:實(shí)現(xiàn)部分的注釋
說明:使用|來引用注釋中的變量名及符號名而不是使用引號。 這會避免二
義性,尤其是當(dāng)符號是一個常用詞匯,這使用語句讀起來很糟糕。 示例:
對于符號count :??// Sometimes we need |count| to be less than zero.或者當(dāng)引用
已經(jīng)包含引號的符號:??// Remember to call |StringWithoutSpaces("foo bar baz")|
3.6建議:程序中變量、方法命名盡量能以字面意思表示功能,對于需要用注
釋來解釋的部分代碼,注釋以如下格式表述:
示例:??/**
*方法或變量說明??* @param參數(shù)1說明(針對方法)??* @param參數(shù)2說明(針
對方法)??* @return若方法有返回值則對返回值作說明*/
3.7建議:每一個方法之前都有一個99字符寬的注釋行,注釋行相對于使用
空行更能??高代碼的 辨識度,當(dāng)一行代碼很長的時候,注釋行也起到了越界檢
測的作用。
注釋行: ///////////////////////////////////////////////////////////////////////////////////// //////////////4.格式
4.1建議:盡量讓你的代碼保持在100列之內(nèi)。
說明:我們深知Objective-C是一門繁冗的語言,在某些情況下略超100列可
能有助于??高可讀 性,但這也只能是特例而已,不能成為開脫 。對于超長的代
碼,我們要懷疑代碼邏輯的簡練性。 設(shè)置方法: Xcode > Preferences > Text
Editing > Show page guide。
空格
4.2規(guī)則:指針變量的星號指示符應(yīng)該緊靠變量。??示例:NSString *text,而不是
NSString* text或NSString * text。
4.3規(guī)則:方法聲明中,-/ +和返回類型之間須使用一個空格。
示例:- (void)doSomethingWithString:(NSString *)theString { ... }
4.4規(guī)則:運(yùn)算符間距1
說明:二元運(yùn)算符和參數(shù)之間需要放置一個空格,一元運(yùn)算符、強(qiáng)制類型轉(zhuǎn)換
和參數(shù)之間不放置空 格。關(guān)鍵字之后圓括號之前,需要放置一個空格。??示例:
void *ptr = &value + 10 * 3; NewType a = (NewType) b;for ( int i = 0; i < 10; i ++ ) { doCoolThings();
}
4.5建議:運(yùn)算符間距2
說明:數(shù)組和字典類型的字面值的 方括號兩邊 各放置一個空格。NSArray
*theShit = @[ @1 , @2, @3 ] ;
字典字面值的鍵和冒號之間沒有空格,冒號和值之間有一個空格。NSDictionary *keyedShit = @{ GHDidCreateStyleGuide: @YES };
C函數(shù)聲明中,左括號的前面 不保留空格,并且函數(shù)名應(yīng)該像類一樣帶有命名
空間標(biāo)識。 良好的風(fēng)格:
void RNCwesomeFunctio n( BOOL hasSomeArgs);長的字面值應(yīng)被拆分為多
行。
良好的風(fēng)格:??NSArray *theShit = @[
@"Got some long string objects in here.", [AndSomeModelObjects too],??@"Moar
strings."
];
NSDictionary *keyedShit = @{??@"this.key": @"corresponds to this value",
@"otherKey": @"remoteData.payload", @"some": @"more",??@"JSON":
@"keys",??@"and": @"stuff",
};
4.6建議:只使用空格,不使用制表符。一次縮進(jìn)兩個空格。
說明:我們使用空格縮進(jìn),不在代碼中使用制表符。在跨平臺開發(fā)中,不同IDE的tab對應(yīng)縮進(jìn)格式 不同。應(yīng)該將編輯器設(shè)置成自動將制表符替換成空格。
4.7建議:類型標(biāo)識符和尖括號內(nèi)的協(xié)議名之間,不能有任何空格。
這條建議適用于類聲明、實(shí)例變量以及方法聲明。
示例:
@interface MyProtocoledClass : NSObject { @private
id delegate_; }
- (void)setDelegate:(id)aDelegate; @end
4.8建議:@public和@private訪問修飾符應(yīng)該以一個空格縮進(jìn)。
示例:??@interface MyClass : NSObject {
@public ...
@private ...
} @end
4.9建議:異常捕獲中,每個@標(biāo)簽應(yīng)該有獨(dú)立的一行,在@與{}之間需要有一個
空格,@catch與被 捕捉到的異常對象的聲明之間也要有一個空格。
如果你決定使用Objective-C的異常,那么就按下面的格式。不過你最好先看
看 避免拋出異常 了 解下為什么不要使用異常。??@try {foo(); }
@catch (NSException *ex) { bar(ex);
}??@finally {
baz(); }
布局與分組
4.10規(guī)則:重載NSObject的方法
如果重載了NSObject類的方法,強(qiáng)烈建議把它們放在@implementation內(nèi)
的起始處,這也是常 見的操作方法。??通常適用(但不局限)于init...,copyWithZone:,以及dealloc方法。所有init...方法應(yīng) 該放在一
起,copyWithZone:緊隨其后,最后才是dealloc方法。
4.11規(guī)則:Delegates和protocol對象聲明在ivar的后面。 說明:delegates的
命名往往比較長。
4.12規(guī)則:屬性聲明和定義的位置
說明:屬性的聲明必須緊靠著類接口中的實(shí)例變量語句塊。屬性的定義必須在@implementation的 類定義的最上方。他們的縮進(jìn)與包含他們的@interface以及@implementation語句一樣。 示例:
@interface MyClass : NSObject { @private
NSString *name_; }
@property(copy, nonatomic) NSString *name; @end@implementation MyClass @synthesize name = name_;
- (id)init { ...??}??@end
4.13建議:當(dāng)需要實(shí)現(xiàn)多個協(xié)議的時候,將每一個協(xié)議名拆分到單獨(dú)的行。
示例:良??好的風(fēng)格:
@interface CustomModelViewController : TTViewController <
TTModelDelegate,??TTURLRequestDelegate
>{風(fēng)格
4.14規(guī)則:關(guān)于方法參數(shù)與調(diào)用
說明:方法有非常多的參數(shù),應(yīng)將每個參數(shù)單獨(dú)拆成一行,且每個參數(shù)前的冒號
對齊。 示例:
- (void)doSomethingWith:(GTMFoo *)theFoo rect:(NSRect)theRect
interval:(float)theInterval {
... }
說明:當(dāng)?shù)谝粋€關(guān)鍵字比其它的短時,保證下一行至少有 直對齊,而不是使用
冒號對齊:示??例:
- (void)short:(GTMFoo *)theFoo longKeyword:(NSRect)theRect
evenLongerKeyword:(float)theInterval {
... }說明:方法調(diào)用應(yīng)盡量保持與方法聲明的格式一致。
4個空格的縮進(jìn)。這樣可以使關(guān)鍵字垂
4.15建議:沒有聲明任何實(shí)例變量的接口,應(yīng)省略空花括號。
示例:良??好的風(fēng)格:??@interface MyClass : NSObject // Does a lot of stuff
- (void)fooBarBam;
@end
不良好的風(fēng)格:??@interface MyClass : NSObject { } // Does a lot of stuff -
(void)fooBarBam;??@end
4.16建議:關(guān)于塊(閉包)
說明:塊(block)適合用在target/selector模式下創(chuàng)建回調(diào)方法時,因?yàn)樗勾a
更易讀。塊 中的代碼應(yīng)該縮進(jìn)4個空格。??取決于塊的長度,下列都是合理的
風(fēng)格準(zhǔn)則:
?如果一行可以寫完塊,則沒必要換行。???如果不得不換行,關(guān)括號應(yīng)與塊聲明
的第一個字符對齊。???塊內(nèi)的代碼須按4空格縮進(jìn)。???如果塊太長,比如超過20行,建議把它定義成一個局部變量,然后再使用該變量。???如果塊不帶參數(shù),
^{之間無須空格。如果帶有參數(shù), ^(之間無須空格,但) {之間須有一個
空格。???塊內(nèi)允許按兩個空格縮進(jìn),但前??是和項(xiàng)目的其它代碼保持一致的縮
進(jìn)風(fēng)格。 示例:??//整個塊在一行??[operation setCompletionBlock:^{ [self
onOperationDone]; }]; //塊內(nèi)容換行,以4個空格縮進(jìn)??[operation
setCompletionBlock:^{
[self.delegate newDataAvailable]; }];
//塊中的C api,風(fēng)格與obj-c一致dispatch_async(fileIOQueue_, ^{
NSString* path = [self sessionFilePath]; if (path) {
// ... }
});??//帶參數(shù)的塊格式,參數(shù)反括號與|{|之間有一個空格[[SessionService
sharedService]
loadWindowWithCompletionBlock:^(SessionWindow *window) { if (window) {[self windowDidLoad:window]; } else {
[self errorLoadingWindow]; }
}];??//塊參數(shù)換行
[[SessionService sharedService] loadWindowWithCompletionBlock:
^(SessionWindow *window) {
if (window) {??[self windowDidLoad:window];
} else {??[self errorLoadingWindow];
} }];
//大的block,應(yīng)該在調(diào)用外面,另行定義void (^largeBlock)(void) = ^{
// ... };
[operationQueue_ addOperationWithBlock:largeBlock];
4.17建議:左右花括號
說明:方法簽名以及其他關(guān)鍵字( if/else/switch/wh ile等)后面跟隨的左花括號
總是和語句出 現(xiàn)于同一行,而右花括號獨(dú)占一行。??示例:
良好的風(fēng)格:??if (user.isHappy) {??//Do something??}??else {??//Do something else??}如果
一個方法內(nèi)有多個功能區(qū)域,可以使用空行分隔功能區(qū)域。
4.18建議:條件體內(nèi)的邏輯塊,需用花括號包圍
說明:即使條件體只需編寫一行代碼也必須使用花括號。 良好的風(fēng)格做法:??if
(!error) {
return success; }
不良的風(fēng)格: if (!error)
return success;或:
if (!error) return success;
4.19建議:內(nèi)部成員變量按邏輯分組.說明:便于理解這個類。
附錄
參考:
1.《Coding Guidelines for Cocoa》??2.《ProgrammingWithObjectiveC》??3.《Google Objective-C Style Guide》??4.《2010-10-24-Three2-Style-Guide》??5.《NYTimes Objective-C Style Guide》??6.《Cocoa Style for Objective-C: Part I》??
7.《Cocoa Style for Objective-C: Part II》