欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Cocoa代码风格指南之排版规范(二)

程序员文章站 2024-01-15 08:02:10
...

本文基于 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];
  1. 如果一行可以写完块,则没必要换行。
  2. 如果不得不换行,关括号应与块声明的第一个字符对齐。
  3. 块内的代码须按 4 空格缩进。
  4. 如果块太长,比如超过 20 行,建议把它定义成一个局部变量,然后再使用该变量。
  5. 如果块不带参数,^{ 之间无须空格。如果带有参数,^( 之间无须空格,但 ) { 之间须有一个空格。
  6. 块内允许按两个空格缩进,但前提是和项目的其它代码保持一致的缩进风格。
  • 如果重载了 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