void *ptr = &value + 10 * 3;
NewType a = (NewType)b;
for (int i = 0; i < 10; i++) {
doCoolThings();
}
數組和字典類型的字面值的方括號兩邊各放置一個空格。
NSArray *theShit = @[ @1, @2, @3 ];
字典字面值的鍵和冒號之間沒有空格,冒號和值之間有一個空格。 NSDictionary *keyedShit = @{ GHDidCreateStyleGuide: @YES }; C函數聲明中,左括號的前面不保留空格,並且函數名應該像類一樣帶有命名空間標識。 良好的風格: void RNCwesomeFunction(BOOL hasSomeArgs); 長的字面值應被拆分為多行。 良好的風格: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個空格縮進。不使用tab縮進。下圖是在Xcode的Preferences進行縮進設置的截圖。 方法簽名以及其他關鍵字(if/else/switch/while等)後面跟隨的左花括號總是和語句出現於同一行,而右花括號獨占一行。 良好的風格:if (user.isHappy) {
//Do something
}
else {
//Do something else
}
如果一個方法內有多個功能區域,可以使用空行分隔功能區域。 每一行代碼不要超過100個字符。 每一個方法之前都有一個99字符寬的注釋行,注釋行相對於使用空行更能提高代碼的辨識度,當一行代碼很長的時候,注釋行也起到了越界檢測的作用。注釋行: /////////////////////////////////////////////////////////////////////////////////////////////////// 條件語句 所有的邏輯塊必須使用花括號包圍,即使條件體只需編寫一行代碼也必須使用花括號。 良好的風格做法:if (!error) {
return success;
}
不良的風格:if (!error)
return success;
或: if (!error) return success; 三元運算符 長的三元運算符應使用圓括號括起來。三元運算符僅用於賦值和做參數。 Blah *a = (stuff == thing ? foo : bar); 合並的nil三元運算符應該盡量避免。 不良的風格: Blah *b = thingThatCouldBeNil ?: defaultValue; 多分支條件應該使用if語句或重構為實例變量。 良好的風格: result = a > b ? x : y; 不良的風格: result = a > b ? x = c > d ? c : d : y; 異常和錯誤處理 不要在流控制語句中使用異常(NSException)。 異常僅用於表明程序員的錯誤。 為了表明一個錯誤,使用NSError *。 當一個方法通過引用返回一個錯誤參數,應該檢測返回值的狀態,而不是錯誤參數的狀態。 良好的風格:NSError *error;
if (![self trySomethingWithError:&error]) {
// Handle Error
}
不良的風格:NSError *error;
[self trySomethingWithError:&error];
if (error) {
// Handle Error
}
在方法執行成功的情況下賦值非Null值給錯誤參數,會使路徑跳轉到假條件分支(隨後程序奔潰)。 代理 除了繼承一個類或實現一個協議,否則在頭文件中僅使用類聲明@class指令,不用#import導入類頭文件。 如果一個delegate只有幾個方法,比如只是提交和取消,推薦使用block編寫動作響應代碼。 由於代理方法的聲明一般都很長,所以必須將代理對象和其他的協議對象放在實例變量定義的下面,否則實例變量定義的對齊方式將會被打亂掉。 當需要實現多個協議的時候,將每一個協議名拆分到單獨的行。 良好的風格:@interface CustomModelViewController : TTViewController <
TTModelDelegate,
TTURLRequestDelegate
> {
方法 一個方法的命名首先描述返回什麼,接著是什麼情況下被返回。方法簽名中冒號的前面描述傳入參數的類型。以下類方法和實例方法命名的格式語法:[object/class thing+condition];
[object/class thing+input:input];
[object/class thing+identifer:input];
Cocoa命名舉例:realPath = [path stringByExpandingTildeInPath];
fullString = [string stringByAppendingString:@"Extra Text"];
object = [array objectAtIndex:3];
// 類方法
newString = [NSString stringWithFormat:@"%f",1.5];
newArray = [NSArray arrayWithObject:newString];
良好的自定義方法命名風格:recipients = [email recipientsSortedByLastName];
newEmail = [CDCEmail emailWithSubjectLine:@"Extra Text"];
emails = [mailbox messagesReceivedAfterDate:yesterdayDate];
當需要獲取對象值的另一種類型的時候,方法命名的格式語法如下:[object adjective+thing];
[object adjective+thing+condition];
[object adjective+thing+input:input];
良好的自定義方法命名風格:capitalized = [name capitalizedString];
rate = [number floatValue];
newString = [string decomposedStringWithCanonicalMapping];
subarray = [array subarrayWithRange:segment];
方法簽名盡量做到含義明確。 不良的風格:-sortInfo // 是返回排序結果還是給info做排序
-refreshTimer // 返回一個用於刷新的定時器還是刷新定時器
-update // 更新什麼,如何更新
良好的風格:-currentSortInfo // "current" 清楚地修飾了名詞SortInfo
-refreshDefaultTimer // refresh是一個動詞。
-updateMenuItemTitle // 一個正在發生的動作
方法類型修飾符+/-後要放置一個空格,各參數名之間也要放置一個空格。 良好的風格: - (void)setExampleText:(NSString *)text image:(UIImage *)image; 如果方法的命名特別長,將方法名拆分成多行。 良好的風格:color = [NSColor colorWithCalibratedHue: 0.10
saturation: 0.82
brightness: 0.89
alpha: 1.00];
不要將私有的實例變量和方法聲明在頭文件中,應將私有變量和方法聲明在實現文件的類擴展內。//MyViewController.h文件
@interface MyViewController : UIViewController<
UITalbeViewDataSource,
UITableViewDelegate> {
@private:
UITableView *_myTableView; // 私有實例變量
}
// 內部使用的屬性
@property (nonatomic,strong) NSNumber *variableUsedInternally;
- (void)sortName; // 只用於內部使用的方法
@end
良好的風格://MyViewController.m文件使用類擴展
@interface MyViewController()<
UITalbeViewDataSource,
UITableViewDelegate> {
UITableView *_myTableView;
// 外部需要訪問的實例變量聲明為屬性,不需要外部訪問的聲明為實例變量
NSNumber * variableUsedInternally;
}
// 從Xcode4.3開始,可以不寫方法的前置聲明,Interface Builder和Storyboard仍然可以找到方法的定義
@end
構造函數通常應該返回實例類型而不是id類型 參數 方法參數名前一般使用的前綴包括“the”、“an”、“new”。 良好的風格:- (void) setTitle: (NSString *) aTitle;
- (void) setName: (NSString *) newName;
- (id) keyForOption: (CDCOption *) anOption
- (NSArray *) emailsForMailbox: (CDCMailbox *) theMailbox;
- (CDCEmail *) emailForRecipients: (NSArray *) theRecipients;
變量 變量的命令應盡量做到自描述。除了在for()循環語句中,單字母的變量應該避免使用(如i,j,k等)。一般循環語句的當前對象的命名前綴包括“one”、“a/an”。對於簡單的單個對象使用“item”命名。 良好的風格: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);
指針變量的星號指示符應該緊靠變量,比如NSString *text,而不是NSString* text或NSString * text。 盡量的使用屬性而非實例變量。除了在初始化方法(init,initWithCoder:等)、dealloc方法以及自定義setter與getter方法中訪問屬性合成的實例變量,其他的情況使用屬性進行訪問。 良好的風格:@interface RNCSection: NSObject
@property (nonatomic) NSString *headline;
@end
不良的風格:@interface RNCSection : NSObject {
NSString *headline;
}
當你使用@synthesize指令時,編譯器會自動為你創建一個下劃線_開頭的的實例變量,所以不需要同時聲明實例變量和屬性。 不良的風格:@interface RNCSection : NSObject {
NSString *headline;
}
@property (nonatomic) NSString *headline;
@end
良好的風格:@interface RNCSection: NSObject
@property (nonatomic) NSString *headline;
@end
不要使用@synthesize除非是編譯器需要。注意在@protoco協議中的@optional可選屬性必須被顯式地使用@synthesize指令合成屬性。 縮略詞 雖然方法命名不應使用縮略詞,然而有些縮略詞在過去被反復的使用,所以使用這些縮略詞能更好的的表達代碼的含義。下表列出了Cocoa可接受的縮略詞。 ........................................................ 以下是一些常用的首字母縮略詞 ASCII PDF XML HTML URL RTF HTTP TIFF JPG PNG GIF LZW ROM RGB CMYK MIDI FTP 命名 方法和變量的命令應該盡可能做到自描述。 良好的風格: UIButton *settingsButton; 不良的風格: UIButton *setBut; 對於NSString、NSArray、NSNumber或BOOL類型,變量的命名一般不需要表明其類型。 良好的風格:NSString *accountName;
NSMutableArray *mailboxes;
NSArray *defaultHeaders;
BOOL userInputWasUpdated;
不良的風格:NSString *accountNameString;
NSMutableArray *mailboxArray;
NSArray *defaultHeadersArray;
BOOL userInputWasUpdatedBOOL;
如果變量不是以上基本常用類型,則變量的命名就應該反映出自身的類型。但有時僅需要某些類的一個實例的情況下,那麼只需要基於類名進行命名。NSImage *previewPaneImage;
NSProgressIndicator *uploadIndicator;
NSFontManager *fontManager; // 基於類名命名
大部分情況下,NSArray或NSSet類型的變量只需要使用單詞復數形式(比如mailboxes),不必在命名中包含“mutable”。如果復數變量不是NSArray或NSSet類型,則需要指定其類型。 良好的風格:NSDictionary * keyedAccountNames;
NSDictionary * messageDictionary;
NSIndexSet * selectedMailboxesIndexSet;
由於Objective-C不支持名字空間,為了防止出現命名空間的沖突,在類名和常類型變量名前添加一個由三個大寫的字母組成的前綴(如RNC),對於Core Data實體名則可以忽略此規則。如果你子類化了標准的Cocoa類,將前綴和父類名合並是一個很好的做法。如繼承UITableView的類可命名為RNCTableView。 常類型變量名的書寫風格采用駝峰式大小寫(第一個單詞的首字母小寫,其余單詞的第一個字母大寫。如firstName而不是first_name或firstname。),並使用關聯的類名作為其命名前綴, 推薦的做法: static const NSTimeInterval RNCArticleViewControllerNavigationFadeAnimationDuration = 0.3; 不推薦的做法: static const NSTimeInterval fadetime = 1.7; 下劃線 使用屬性的時候,實例變量應該使用self.進行訪問和設值。局部變量的命令不要包含下劃線。實例變量的命名必須使用下劃線_作為前綴,這樣可以縮小Xcode自動完成的選項取值范圍。 注釋 在需要的時候,注釋可對代碼做必要的解釋。更新代碼時一定要更新注釋,防止對代碼造成誤解。 使用javadoc風格的文檔注釋語法。注釋的第一行是對注釋API的總結,隨後的注釋行是對代碼更多細節的解釋。 良好的風格:/**
* 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;
init與dealloc dealloc方法應該被放置在實現方法的頂部,直接在@synthesize或@dynamic語句之後。init方法應該被放置在dealloc方法的下面。 init方法的結構看上去應該像這樣:- (instancetype)init {
self = [super init]; // or call the designated initalizer
if (self) {
// Custom initialization
}
return self;
}
字面值 對於NSString,NSDictionary,NSArray和NSNumber類,當需要創建這些類的不可變實例時,應該使用這些類的字面值表示形式。使用字面值表示的時候nil不需要傳入NSArray和NSDictionary中作為字面值。這種語法兼容老的iOS版本,因此可以在iOS5或者更老的版本中使用它。 良好的風格:NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingZIPCode = @10018;
不良的風格:NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
NSNumber *buildingZIPCode = [NSNumber numberWithInteger:10018];
如非必要,避免使用特定類型的數字(相較於使用5.3f,應使用5.3)。 CGRect函數 相較於使用結構體輔助函數(如CGRectMake()函數),優先使用C99結構體初始化語法。 CGRect rect = {.origin.x = 3.0, .origin.y = 12.0, .size.width = 15.0, .size.height = 80.0 }; 當訪問CGRect結構體的x、y、width、height成員時,應使用CGGeometry函數,不直接訪問結構體成員。蘋果對CGGeometry函數的介紹: All functions described in this reference that take CGRect data structures as inputs implicitly standardize those rectangles before calculating their results. For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics. 良好的風格:CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
不良的風格:CGRect frame = self.view.frame;
CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;
常量 優先使用常類型變量,而不是內嵌的字符串字面值或數字,因為常類型變量能很容易的復用常用的變量值(如π),同時可以快速地修改值而無需查找替換。常類型變量應該聲明為static類型,不要使用#define,除非常類型變量被作為宏使用。 良好的風格:static NSString * const RNCAboutViewControllerCompanyName = @"The New York Times Company";
static const CGFloat RNCImageThumbnailHeight = 50.0;
不良的風格:#define CompanyName @"The New York Times Company"
#define thumbnailHeight 2
枚舉類型 當使用enum關鍵字時,推薦使用蘋果最新引入的固定基礎類型語法,因為這將獲得強類型檢查與代碼完成功能。SDK現在包含了一個固定基礎類型的宏——NS_ENUM()。 NS_ENUM是在iOS6中開始引入的,為了支持之前的iOS版本,使用簡單的內聯方法:#ifndef NS_ENUM
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#endif
良好的風格:typedef NS_ENUM(NSInteger, RNCAdRequestState) {
RNCAdRequestStateInactive,
RNCAdRequestStateLoading
};
私有屬性 私有屬性應該被聲明在實現文件的類擴展中(即匿名的category)。不要將私有屬性聲明在命名的category(如RNCPrivate或private),除非是擴展其他類。 良好的風格:@interface NYTAdvertisement ()
@property (nonatomic, strong) GADBannerView *googleAdView;
@property (nonatomic, strong) ADBannerView *iAdView;
@property (nonatomic, strong) UIWebView *adXWebView;
@end
圖片的命名 圖片的命名應該保持一致,以圖片的用途描述作為圖片文件名。文件名的命名使用駝峰式大小寫風格,文件名後可跟隨一個自定義的類名或者是自定義的屬性名(如果有屬性名)、也可以再跟上顏色描述以及/或者位置、圖片的最終狀態。if (!someObject) {
}
不良的風格:if (someObject == nil) {
}
對於一個BOOL值:兩種最佳實踐:if (isAwesome)
if (![someObject boolValue])
不良的風格:if ([someObject boolValue] == NO)
if (isAwesome == YES) // Never do this.
如果一個BOOL類型的屬性名是一個形容詞,忽略屬性名的“is”前綴是允許的,但需要為訪問器指定約定的方法名,比如: @property (assign, getter=isEditable) BOOL editable; 單例 應該使用線程安全的模式創建共享的單例實例。+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
附錄 Xcode主題 大部分的開發者都使用Xcode默認的字體顏色主題,其實好的主題不僅能提高源代碼的辨識度,同時也增添了編碼的樂趣。 代碼片段 熟練使用代碼片段庫可以提高編碼的速度。Xcode4中,打開一個項目並讓右側編輯區可視,然後點擊右側底部面板的第四個{}圖標,打開代碼片段庫,你可以將常用的代碼拖入其中。