本文基于 Google 的代码风格指南中关于排版规范的部分的总结,其中部门内容具有主观性。本文所有代码的排版均为建议的格式,如有文字上疏漏的地方,可以参考任何一段代码。首先通过一段代码来了解基本的排版格式。
- [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个空格来进行缩进,并且将编辑器设置成自动将制表符替换成空格。但这不符合大多数 Objective-C 程序员的习惯。所以还是建议所有的缩进都使用单个制表符。
行宽 [Google][General]
尽量让你的代码保持在 80 列之内。Objective-C 是一门繁冗的语言,在某些情况下略超 80 列可能有助于提高可读性,但这也只能是特例而已,不能成为开脱。如果阅读代码的人认为把把某行行宽保持在 80 列仍然有不失可读性,你应该按他们说的去做。这条规则是有争议的,但很多已经存在的代码坚持了本规则,所以 Google 觉得保证一致性更重要。通过设置 Xcode > Preferences > Text Editing > Show page guide,来使越界更容易被发现。这条规则对我个人有很强的约束,但很多代码难以实现80列,所以在这里还有很多值得探索的写法。
属性 [General]
@property (nonatomic, strong) NSString *string;
@property (nonatomic, weak) id<XXDelegate> delegate;
- property 后留空格
- nonatomic 放在修饰符第一位
- 内存管理修饰符放在第二位
- 修饰符中间在“,”后留空格
- 修饰符“()”后留空格
- 所有变量的类名后留空格
- 类型标识符和尖括号内的协议名之间不能有任何空格
方法 [General]
- (void)doSomethingWith:(GTMFoo *)theFoo
rect:(NSRect)theRect
interval:(float)theInterval {
// TODO
}
- (void)short:(GTMFoo *)theFoo
longKeyword:(NSRect)theRect
evenLongerKeyword:(float)theInterval {
// TODO
}
- 方法返回值前留空格
- 方法返回值后不留空格
- 左括号和方法名在同行并有空格隔开
- 多个参数的方法换行并以冒号对齐
- 换行后如有某行过长导致冒号无法对齐则整体缩进一个制表符
- 方法在声明、实现、调用时均上述规则
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 行,建议把它定义成一个局部变量,然后再使用该变量。
- 如果块不带参数,^{ 之间无须空格。如果带有参数,^( 之间无须空格,但 ) { 之间须有一个空格。
- 块内允许按两个空格缩进,但前提是和项目的其它代码保持一致的缩进风格。
如果重载了 NSObject 类的方法,强烈建议把它们放在 @implementation 内的起始处,这也是常见的操作方法。通常适用(但不局限)于 init...,copyWithZone:,以及 dealloc 方法。所有 init... 方法应该放在一起,copyWithZone: 紧随其后,最后才是 dealloc 方法。 [Google][General]
指定初始化方法使用 NS_DESIGNATED_INITIALIZER 标示。 [General]
写子类时如果需要 init… 方法,记得重载父类的指定构造函数。 [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