代码格式
缩进
不要在工程里使用Tab键,使用空格来进行缩进。不要去修改Xcode > Preferences > Text Editing里的Tab和自动缩进的默认的 4 个空格设置,即使用 Xcode 的默认设置即可。
方法的书写
一个典型的 Objective-C 方法应该是这样的:
- (void)writeVideoFrameWithData:(NSData *)frameData timeStamp:(int)timeStamp {
...
}
在-和(void)之间应该有一个空格,第一个大括号{的位置在方法所在行的末尾,同样应该有一个空格。
如果一个方法有特别多的参数或者名称很长,应该将其按照:来对齐分行显示:
-(id)initWithModel:(IPCModle)model
ConnectType:(IPCConnectType)connectType
Resolution:(IPCResolution)resolution
AuthName:(NSString *)authName
Password:(NSString *)password
MAC:(NSString *)mac
AzIp:(NSString *)az_ip
AzDns:(NSString *)az_dns
Token:(NSString *)token
Email:(NSString *)email
Delegate:(id<IPCConnectHandlerDelegate>)delegate;
在分行时,如果第一段名称过短,后续名称可以以Tab的长度(4个空格)为单位进行缩进:
- (void)short:(GTMFoo *)theFoo
longKeyword:(NSRect)theRect
evenLongerKeyword:(float)theInterval
error:(NSError **)theError {
...
}
方法调用
方法调用的格式和书写差不多,可以按照方法的长短来选择写在一行或者分成多行:
//写在一行
[myObject doFooWith:arg1 name:arg2 error:arg3];
//分行写,按照':'对齐
[myObject doFooWith:arg1
name:arg2
error:arg3];
//第一段名称过短的话后续可以进行缩进
[myObj short:arg1
longKeyword:arg2
evenLongerKeyword:arg3
error:arg4];
以下写法是错误的:
//错误,要么写在一行,要么全部分行
[myObject doFooWith:arg1 name:arg2
error:arg3];
[myObject doFooWith:arg1
name:arg2 error:arg3];
//错误,按照':'来对齐,而不是关键字
[myObject doFooWith:arg1
name:arg2
error:arg3];
@public和@private标记符
@public和@private标记符应该以 一个空格 来进行缩进:
@interface MyClass : NSObject {
@public
...
@private
...
}
@end
协议(Protocols)
在书写协议的时候注意用<>括起来的协议和类型名之间是没有空格的,比如IPCConnectHandler(),这个规则适用所有书写协议的地方,包括方法声明、类声明、实例变量等等:
@interface MyProtocoledClass : NSObject<NSWindowDelegate> {
@private
id<MyFancyDelegate> _delegate;
}
- (void)setDelegate:(id<MyFancyDelegate>)aDelegate;
@end
闭包(Blocks)
根据block的长度,有不同的书写规则:
- 较短的block可以写在一行内。
- 如果分行显示的话,block的右括号}应该和调用block那行代码的第一个非空字符对齐。
- block内的代码采用4个空格的缩进。
- 如果block过于庞大,应该单独声明成一个变量来使用。
- 和(之间,和{之间都没有空格,参数列表的右括号)和{之间有一个空格。
//较短的block写在一行内
[operation setCompletionBlock:^{ [self onOperationDone]; }];
//分行书写的block,内部使用4空格缩进
[operation setCompletionBlock:^{
[self.delegate newDataAvailable];
}];
//使用C语言API调用的block遵循同样的书写规则
dispatch_async(_fileIOQueue, ^{
NSString* path = [self sessionFilePath];
if (path) {
// ...
}
});
//较长的block关键字可以缩进后在新行书写,注意block的右括号'}'和调用block那行代码的第一个非空字符对齐
[[SessionService sharedService]
loadWindowWithCompletionBlock:^(SessionWindow *window) {
if (window) {
[self windowDidLoad:window];
} else {
[self errorLoadingWindow];
}
}];
//较长的block参数列表同样可以缩进后在新行书写
[[SessionService sharedService]
loadWindowWithCompletionBlock:
^(SessionWindow *window) {
if (window) {
[self windowDidLoad:window];
} else {
[self errorLoadingWindow];
}
}];
//庞大的block应该单独定义成变量使用
void (^largeBlock)(void) = ^{
// ...
};
[_operationQueue addOperationWithBlock:largeBlock];
//在一个调用中使用多个block,注意到他们不是像方法那样通过':'对齐的,而是同时进行了4个空格的缩进
[myObject doSomethingWith:arg1
firstBlock:^(Foo *a) {
// ...
}
secondBlock:^(Bar *b) {
// ...
}];
数据结构的字面量写法
应该使用可读性更好的字面量来构造NSArray,NSDictionary等数据结构,避免使用冗长的alloc,init方法。
如果构造代码写在一行,需要在括号两端留有一个空格,使得被构造的元素于与构造语法区分开来:
//正确,在字面量的"[]"或者"{}"两端留有空格
NSArray *array = @[ [foo description], @"Another String", [bar description] ];
NSDictionary *dict = @{ NSForegroundColorAttributeName : [NSColor redColor] };
//不正确,不留有空格降低了可读性
NSArray* array = @[[foo description], [bar description]];
NSDictionary* dict = @{NSForegroundColorAttributeName: [NSColor redColor]};
如果构造代码不写在一行内,构造元素需要使用 两个空格 来进行缩进,右括号]或者}写在新的一行,并且与调用字面量那行代码的第一个非空字符对齐:
NSArray *array = @[
@"This",
@"is",
@"an",
@"array"
];
NSDictionary *dictionary = @{
NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
NSForegroundColorAttributeName : fontColor
};
构造字典时,字典的Key和Value与中间的冒号:都要留有一个空格,多行书写时,也可以将Value对齐:
//正确,冒号':'前后留有一个空格
NSDictionary *option1 = @{
NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
NSForegroundColorAttributeName : fontColor
};
//正确,按照Value来对齐
NSDictionary *option2 = @{
NSFontAttributeName : [NSFont fontWithName:@"Arial" size:12],
NSForegroundColorAttributeName : fontColor
};
//错误,冒号前应该有一个空格
NSDictionary *wrong = @{
AKey: @"b",
BLongerKey: @"c",
};
//错误,每一个元素要么单独成为一行,要么全部写在一行内
NSDictionary *alsoWrong= @{ AKey : @"a",
BLongerKey : @"b" };
//错误,在冒号前只能有一个空格,冒号后才可以考虑按照Value对齐
NSDictionary *stillWrong = @{
AKey : @"b",
BLongerKey : @"c",
};
nil检查
因为在 Objective-C 中向nil对象发送命令是不会抛出异常或者导致崩溃的,只是完全的“什么都不干”,所以,只在程序中使用nil来做逻辑上的检查。
另外,不要使用诸如nil == Object或者Object == nil的形式来判断。
//正确,直接判断
if (!objc) {
...
}
//错误,不要使用nil == Object的形式
if (nil == objc) {
...
}