本文基于 Google 的代碼風格指南中關于排版規(guī)范的部分的總結,其中部門內容具有主觀性。本文所有代碼的排版均為建議的格式,如有文字上疏漏的地方,可以參考任何一段代碼。首先通過一段代碼來了解基本的排版格式。
- [Apple]:Apple 明確給出建議
- [Google]:Google 明確給出建議
- [General]:通用做法(主觀)
#import <Foundation/Foundation.h>
@interface Foo : NSObject
+ (instancetype)fooWithBar:(NSString *)bar;
- (instancetype)initWithBar:(NSString *)bar;
- (NSString *)bar;
- (void)setBar:(NSString *)bar;
- (BOOL)doWorkWithBlah:(NSString *)blah;
@end
#import "Foo.h"
@implementation Foo {
NSString *bar;
NSString *bam;
}
+ (id)fooWithBar:(NSString *)bar {
return [[self alloc] initWithBar:bar];
}
- (id)init {
return [self initWithBar:nil];
}
- (id)initWithBar:(NSString *)bar {
self = [super init]
if (self) {
_bar = [bar copy];
_bam = [[NSString alloc] initWithFormat:@"hi %d", 3];
}
return self;
}
- (NSString *)bar {
return _bar;
}
- (void)setBar:(NSString *)bar {
_bar = [bar copy];
}
- (BOOL)doWorkWithBlah:(NSString *)blah {
return NO;
}
@end
上述代碼中的所有換行、空格、縮進都為建議的格式。下邊將進行更加詳細的描述。
空格和制表符 [Google][General]
Google 建議使用2個空格來進行縮進,并且將編輯器設置成自動將制表符替換成空格。但這不符合大多數(shù) Objective-C 程序員的習慣。所以還是建議所有的縮進都使用單個制表符。
行寬 [Google][General]
盡量讓你的代碼保持在 80 列之內。Objective-C 是一門繁冗的語言,在某些情況下略超 80 列可能有助于提高可讀性,但這也只能是特例而已,不能成為開脫。如果閱讀代碼的人認為把把某行行寬保持在 80 列仍然有不失可讀性,你應該按他們說的去做。這條規(guī)則是有爭議的,但很多已經存在的代碼堅持了本規(guī)則,所以 Google 覺得保證一致性更重要。通過設置 Xcode > Preferences > Text Editing > Show page guide,來使越界更容易被發(fā)現(xiàn)。這條規(guī)則對我個人有很強的約束,但很多代碼難以實現(xiàn)80列,所以在這里還有很多值得探索的寫法。
屬性 [General]
@property (nonatomic, strong) NSString *string;
@property (nonatomic, weak) id<XXDelegate> delegate;
- property 后留空格
- nonatomic 放在修飾符第一位
- 內存管理修飾符放在第二位
- 修飾符中間在“,”后留空格
- 修飾符“()”后留空格
- 所有變量的類名后留空格
- 類型標識符和尖括號內的協(xié)議名之間不能有任何空格
方法 [General]
- (void)doSomethingWith:(GTMFoo *)theFoo
rect:(NSRect)theRect
interval:(float)theInterval {
// TODO
}
- (void)short:(GTMFoo *)theFoo
longKeyword:(NSRect)theRect
evenLongerKeyword:(float)theInterval {
// TODO
}
- 方法返回值前留空格
- 方法返回值后不留空格
- 左括號和方法名在同行并有空格隔開
- 多個參數(shù)的方法換行并以冒號對齊
- 換行后如有某行過長導致冒號無法對齊則整體縮進一個制表符
- 方法在聲明、實現(xiàn)、調用時均上述規(guī)則
Block [Google][General]
// The entire block fits on one line.
[operation setCompletionBlock:^{ [self onOperationDone]; }];
// The block can be put on a new line, indented four spaces, with the
// closing brace aligned with the first character of the line on which
// block was declared.
[operation setCompletionBlock:^{
[self.delegate newDataAvailable];
}];
// Using a block with a C API follows the same alignment and spacing
// rules as with Objective-C.
dispatch_async(fileIOQueue_, ^{
NSString* path = [self sessionFilePath];
if (path) {
// TODO
}
});
// An example where the parameter wraps and the block declaration fits
// on the same line. Note the spacing of |^(SessionWindow *window) {|
// compared to |^{| above.
[[SessionService sharedService]
loadWindowWithCompletionBlock:^(SessionWindow *window) {
if (window) {
[self windowDidLoad:window];
} else {
[self errorLoadingWindow];
}
}];
// An example where the parameter wraps and the block declaration does
// not fit on the same line as the name.
[[SessionService sharedService]
loadWindowWithCompletionBlock:
^(SessionWindow *window) {
if (window) {
[self windowDidLoad:window];
} else {
[self errorLoadingWindow];
}
}];
// Large blocks can be declared out-of-line.
void (^largeBlock)(void) = ^{
// TODO
};
[operationQueue_ addOperationWithBlock:largeBlock];
- 如果一行可以寫完塊,則沒必要換行。
- 如果不得不換行,關括號應與塊聲明的第一個字符對齊。
- 塊內的代碼須按 4 空格縮進。
- 如果塊太長,比如超過 20 行,建議把它定義成一個局部變量,然后再使用該變量。
- 如果塊不帶參數(shù),^{ 之間無須空格。如果帶有參數(shù),^( 之間無須空格,但 ) { 之間須有一個空格。
- 塊內允許按兩個空格縮進,但前提是和項目的其它代碼保持一致的縮進風格。
如果重載了 NSObject 類的方法,強烈建議把它們放在 @implementation 內的起始處,這也是常見的操作方法。通常適用(但不局限)于 init...,copyWithZone:,以及 dealloc 方法。所有 init... 方法應該放在一起,copyWithZone: 緊隨其后,最后才是 dealloc 方法。 [Google][General]
指定初始化方法使用 NS_DESIGNATED_INITIALIZER 標示。 [General]
寫子類時如果需要 init… 方法,記得重載父類的指定構造函數(shù)。 [Google][General]
// UIView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// TODO
}
return self;
}
博客:xuyafei.cn
簡書:jianshu.com/users/2555924d8c6e
微博:weibo.com/xuyafei86
Github:github.com/xiaofei86