ObjC Style Guide

Objective-C Style Guide

最近看了很多OC方面的编码风格推荐, 个人认为编码规范不管对于个人开发还是团队开发都是非常重要的, 这里总结出来, 给大家提供一个参考.

语言

使用美式英语.

1
2
3
4
5
// 推荐
UIColor *myColor = [UIColor whiteColor];
// 不推荐
UIColor *myColour = [UIColor whiteColor];

组织代码

使用 #pragma mark - 组织代码.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#pragma mark - Lifecycle
- (instancetype)init {}
- (void)dealloc {}
- (void)viewDidLoad {}
- (void)viewWillAppear:(BOOL)animated {}
- (void)viewDidAppear:(BOOL)animated {}
- (void)didReceiveMemoryWarning {}
#pragma mark - Custom Accessors
- (void)setCustomProperty:(id)value {}
- (id)customProperty {}
#pragma mark - IBActions
- (IBAction)submitData:(id)sender {}
#pragma mark - Public
- (void)publicMethod {}
#pragma mark - Private
- (void)privateMethod {}
#pragma mark - UITableViewDataSource
//...
#pragma mark - UITableViewDelegate
//...
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {}
#pragma mark - NSObject
- (NSString *)description {}

条件语句

1
2
3
4
5
6
7
8
9
10
11
// 推荐
if (!error) {
return success;
}
// 不推荐
if (!error)
return success;
// 或
if (!error) return success;

方法

方法声明中, 应该在(-/+ 符号)的后面留一个空格.

1
- (void)setExampleText:(NSString *)text image:(UIImage *)image;

变量

  • 变量应该尽可能的用描述性的语言命名, 应该避免使用单字母来命名变量除了用于 for() 循环里.

  • *表示变量是一个指针, 例如 NSString *text 不要写成 NSString* text, 也不要写成 NSString * text, 除非是在定义常量的情况下.

  • 属性定义无论在何时都应该是用来代替实例变量定义, 应该避免直接使用实例变量, 除非在初始化方法中(init, initWithCoder:等), dealloc 方法中和实例变量对应的 settergetter 方法中.

1
2
3
4
5
6
7
8
9
10
11
// 推荐
@interface NYTSection: NSObject
@property (nonatomic) NSString *headLine;
@end
// 不推荐
@interface NYTSection : NSObject {
NSString * headLine;
}

命名

遵循 Apple 命名规范

1
2
3
4
5
// 推荐
UIButton *settingsButton;
// 不推荐
UIButton *setBut;

字母前缀(例如SR)应该用于类名和常量, 但是 Core Data 的实体名应该忽略前缀.
常量应该使用驼峰式命名规范, 要与类名有相关性要见面知意.

1
2
3
4
5
// 推荐
static const NSTimeInterval SRNavigationFadeAnimationDuration = 0.2;
// 不推荐
static const NSTimeInterval fadetime = 1.7;
  • 属性和局部变量应该使用开头字母小写的驼峰式命名规范.
  • 实例变量应该使用开头字母小写的驼峰式命名规范,并且前缀是下划线.
  • 局部变量不应该包含下划线.

注释

注释应该是用来解释为什么, 而不是用来说明是什么.

init 和 dealloc
dealloc 方法应该放在 implementation 的上面, init 应该直接放在 dealloc 方法的下面.

1
2
3
4
5
6
7
- (instancetype)init {
self = [super init]; // or call the designated initalizer
if (self) {
// Custom initialization
}
return self;
}

文字变量

  • NSString, NSDictionary, NSArray, 和 NSNumber 这些文字变量无论在何时都应该被用来创建不可变的实例对象.
  • 注意不要把 nil 传入到了 NSArrayNSDictionary 中,因为这样会导致c程序崩溃.
1
2
3
4
5
6
7
8
9
10
11
// 推荐
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingZIPCode = @10018;
// 不推荐
NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
NSNumber *buildingZIPCode = [NSNumber numberWithInteger:10018];

CGRect 函数

当访问 x, y, widthheight,应该使用 CGGeometry 函数,而不应该直接访问结构的成员.

1
2
3
4
5
6
7
8
9
10
11
12
13
// 推荐
CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
// 不推荐
CGRect frame = self.view.frame;
CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;

常量

常量和宏都可以的情况下, 推荐使用常量.

1
2
3
4
5
6
7
// 推荐
static NSString * const NYTAboutViewControllerCompanyName = @"The New York Times Company";
static const CGFloat NYTImageThumbnailHeight = 50.0;
// 不推荐
#define CompanyName @"The New York Times Company"
#define thumbnailHeight 2

枚举类型

1
2
3
4
typedef NS_ENUM(NSInteger, SRRequestState) {
SRRequestStateInactive,
SRRequestStateLoading
};

Case 语句

当在switch中使用枚举类型的时候 default 并不需要.

1
2
3
4
5
6
7
8
9
10
11
12
SRLeftMenuTopItemType menuType = SRTLeftMenuTopItemMain;
switch (menuType) {
case RWTLeftMenuTopItemMain:
// ...
break;
case RWTLeftMenuTopItemShows:
// ...
break;
case RWTLeftMenuTopItemSchedule:
// ...
break;
}

布尔值判断

  • 既然 nil 等同于 NO 那就没有必要在条件语句中进行比较
  • 永远不要直接把某些东西与 YES 相比较.
1
2
3
4
5
6
7
// 推荐
if (!someObject) {
}
// 不推荐
if (someObject == nil) {
}

BOOL 的例子

1
2
3
4
5
6
7
// 推荐
if (isAwesome)
if (![someObject boolValue])
// 不推荐
if (isAwesome == YES)
if ([someObject boolValue] == NO)

BOOL 属性的名字应该取名为形容词, 属性名可以忽略 ‘is’ 前缀, 但 getter 方法要使用传统的命名.

1
@property (assign, getter=isEditable) BOOL editable;

单例

单例对象应该使用安全线程机制来创建它们的共享实例.

1
2
3
4
5
6
7
8
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}

这能够防止某些时候可能出现各种程序崩溃的问题

(未完持续更新)

参考

官方 OC Style Guides:

其他 OC Style Guides: