代码格式

使用空格而不是制表符Tab

不要在工程里使用Tab键,使用空格来进行缩进。在Xcode > Preferences > Text Editing将Tab和自动缩进都设置为4个空格。(Google的标准是使用两个空格来缩进,但这里还是推荐使用Xcode默认的设置。

每一行的最大长度

同样的,在Xcode > Preferences > Text Editing > Page guide at column:中将最大行长设置为80,过长的一行代码将会导致可读性问题。

函数的书写

一个典型的Objective-C函数应该是这样的:

  1. - (void)writeVideoFrameWithData:(NSData *)frameData timeStamp:(int)timeStamp {
  2. ...
  3. }

-(void)之间应该有一个空格,第一个大括号{的位置在函数所在行的末尾,同样应该有一个空格。(我司的C语言规范要求是第一个大括号单独占一行,但考虑到OC较长的函数名和苹果SDK代码的风格,还是将大括号放在行末。

如果一个函数有特别多的参数或者名称很长,应该将其按照:来对齐分行显示:

  1. -(id)initWithModel:(IPCModle)model
  2. ConnectType:(IPCConnectType)connectType
  3. Resolution:(IPCResolution)resolution
  4. AuthName:(NSString *)authName
  5. Password:(NSString *)password
  6. MAC:(NSString *)mac
  7. AzIp:(NSString *)az_ip
  8. AzDns:(NSString *)az_dns
  9. Token:(NSString *)token
  10. Email:(NSString *)email
  11. Delegate:(id<IPCConnectHandlerDelegate>)delegate;

在分行时,如果第一段名称过短,后续名称可以以Tab的长度(4个空格)为单位进行缩进:

  1. - (void)short:(GTMFoo *)theFoo
  2. longKeyword:(NSRect)theRect
  3. evenLongerKeyword:(float)theInterval
  4. error:(NSError **)theError {
  5. ...
  6. }

函数调用

函数调用的格式和书写差不多,可以按照函数的长短来选择写在一行或者分成多行:

  1. //写在一行
  2. [myObject doFooWith:arg1 name:arg2 error:arg3];
  3. //分行写,按照':'对齐
  4. [myObject doFooWith:arg1
  5. name:arg2
  6. error:arg3];
  7. //第一段名称过短的话后续可以进行缩进
  8. [myObj short:arg1
  9. longKeyword:arg2
  10. evenLongerKeyword:arg3
  11. error:arg4];

以下写法是错误的:

  1. //错误,要么写在一行,要么全部分行
  2. [myObject doFooWith:arg1 name:arg2
  3. error:arg3];
  4. [myObject doFooWith:arg1
  5. name:arg2 error:arg3];
  6. //错误,按照':'来对齐,而不是关键字
  7. [myObject doFooWith:arg1
  8. name:arg2
  9. error:arg3];

@public@private标记符

@public@private标记符应该以一个空格来进行缩进:

  1. @interface MyClass : NSObject {
  2. @public
  3. ...
  4. @private
  5. ...
  6. }
  7. @end

协议(Protocols)

在书写协议的时候注意用<>括起来的协议和类型名之间是没有空格的,比如IPCConnectHandler()<IPCPreconnectorDelegate>,这个规则适用所有书写协议的地方,包括函数声明、类声明、实例变量等等:

  1. @interface MyProtocoledClass : NSObject<NSWindowDelegate> {
  2. @private
  3. id<MyFancyDelegate> _delegate;
  4. }
  5. - (void)setDelegate:(id<MyFancyDelegate>)aDelegate;
  6. @end

闭包(Blocks)

根据block的长度,有不同的书写规则:

  • 较短的block可以写在一行内。
  • 如果分行显示的话,block的右括号}应该和调用block那行代码的第一个非空字符对齐。
  • block内的代码采用4个空格的缩进。
  • 如果block过于庞大,应该单独声明成一个变量来使用。
  • ^(之间,^{之间都没有空格,参数列表的右括号){之间有一个空格。
  1. //较短的block写在一行内
  2. [operation setCompletionBlock:^{ [self onOperationDone]; }];
  3. //分行书写的block,内部使用4空格缩进
  4. [operation setCompletionBlock:^{
  5. [self.delegate newDataAvailable];
  6. }];
  7. //使用C语言API调用的block遵循同样的书写规则
  8. dispatch_async(_fileIOQueue, ^{
  9. NSString* path = [self sessionFilePath];
  10. if (path) {
  11. // ...
  12. }
  13. });
  14. //较长的block关键字可以缩进后在新行书写,注意block的右括号'}'和调用block那行代码的第一个非空字符对齐
  15. [[SessionService sharedService]
  16. loadWindowWithCompletionBlock:^(SessionWindow *window) {
  17. if (window) {
  18. [self windowDidLoad:window];
  19. } else {
  20. [self errorLoadingWindow];
  21. }
  22. }];
  23. //较长的block参数列表同样可以缩进后在新行书写
  24. [[SessionService sharedService]
  25. loadWindowWithCompletionBlock:
  26. ^(SessionWindow *window) {
  27. if (window) {
  28. [self windowDidLoad:window];
  29. } else {
  30. [self errorLoadingWindow];
  31. }
  32. }];
  33. //庞大的block应该单独定义成变量使用
  34. void (^largeBlock)(void) = ^{
  35. // ...
  36. };
  37. [_operationQueue addOperationWithBlock:largeBlock];
  38. //在一个调用中使用多个block,注意到他们不是像函数那样通过':'对齐的,而是同时进行了4个空格的缩进
  39. [myObject doSomethingWith:arg1
  40. firstBlock:^(Foo *a) {
  41. // ...
  42. }
  43. secondBlock:^(Bar *b) {
  44. // ...
  45. }];

数据结构的语法糖

应该使用可读性更好的语法糖来构造NSArrayNSDictionary等数据结构,避免使用冗长的alloc,init方法。

如果构造代码写在一行,需要在括号两端留有一个空格,使得被构造的元素于与构造语法区分开来:

  1. //正确,在语法糖的"[]"或者"{}"两端留有空格
  2. NSArray *array = @[ [foo description], @"Another String", [bar description] ];
  3. NSDictionary *dict = @{ NSForegroundColorAttributeName : [NSColor redColor] };
  4. //不正确,不留有空格降低了可读性
  5. NSArray* array = @[[foo description], [bar description]];
  6. NSDictionary* dict = @{NSForegroundColorAttributeName: [NSColor redColor]};

如果构造代码不写在一行内,构造元素需要使用两个空格来进行缩进,右括号]或者}写在新的一行,并且与调用语法糖那行代码的第一个非空字符对齐:

  1. NSArray *array = @[
  2. @"This",
  3. @"is",
  4. @"an",
  5. @"array"
  6. ];
  7. NSDictionary *dictionary = @{
  8. NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
  9. NSForegroundColorAttributeName : fontColor
  10. };

构造字典时,字典的Key和Value与中间的冒号:都要留有一个空格,多行书写时,也可以将Value对齐:

  1. //正确,冒号':'前后留有一个空格
  2. NSDictionary *option1 = @{
  3. NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
  4. NSForegroundColorAttributeName : fontColor
  5. };
  6. //正确,按照Value来对齐
  7. NSDictionary *option2 = @{
  8. NSFontAttributeName : [NSFont fontWithName:@"Arial" size:12],
  9. NSForegroundColorAttributeName : fontColor
  10. };
  11. //错误,冒号前应该有一个空格
  12. NSDictionary *wrong = @{
  13. AKey: @"b",
  14. BLongerKey: @"c",
  15. };
  16. //错误,每一个元素要么单独成为一行,要么全部写在一行内
  17. NSDictionary *alsoWrong= @{ AKey : @"a",
  18. BLongerKey : @"b" };
  19. //错误,在冒号前只能有一个空格,冒号后才可以考虑按照Value对齐
  20. NSDictionary *stillWrong = @{
  21. AKey : @"b",
  22. BLongerKey : @"c",
  23. };