iOS 代码规范

这是我为团队制定的 iOS 代码规范,供大家参考。

文档说明

Version Time Author
0.1 Alpha 2014-08-21 StoneArk
0.2 Beta 2014-09-02 StoneArk
0.3 Beta 2014-09-15 StoneArk
1.0 2014-09-16 StoneArk

基本原则

求同存异。

合理的编码风格不只一个,尊重每位开发人员的编码习惯。但不合理的编码习惯必须避免。

命名规则

  • 命名规则
范围 命名规则 示例
变量名、方法名 驼峰式命名 (小驼峰式命名) onlineCount
- (void)viewDidLoad
类名、枚举类型名 Pascal 命名 MainViewController
FruitType
常量 全部大写或k开头的驼峰式命名 FONTNAME
kFontName
宏定义 全部大写 LOCALDEBUG
枚举值 要有枚举类型前缀 FruitType 枚举类型的枚举值应为 FruitTypeApple, FruitTypeBanana
  • 命名约定
范围 命名约定 示例
数组 arr...
...Array
arrImage
imageArray
字符串 str...
...String
strTitle
titleString
布尔变量 is... isShown
按钮 btn...
...Button
btnSubmit
submitButton
标签 lbl...
...Label
lblTitle
titleLabel
滚动视图 scrView...
...ScrollView
scrViewContent
contentScrollView
按钮点击 btn...Click
...Action
- (void)btnSubmitClick
- (void)submitAction
  • 注意
    1. 应为有意义的命名,除循环变量外,不得使用 i, j, k 等单字符作为名称。
    2. 不得使用关键字、保留字命名,如 id, const, bool 等。
    3. 尽可能地避免出现魔术数字,应采用枚举类型、 常量、宏定义等方式赋予数字以具体意义。
    4. 除非必要(如名称过长或已为众所周知的缩写),命名不应使用缩写。
    5. 除非必要(如特定名称或没有合适的单词),命名应采用规范的英文单词,避免采用汉语拼音。

代码缩进

基本要求

所有代码必须有符合其层次结构的缩进,缩进使用 4 个空格符

大括号的处理

(1)允许的形式有 K&R、Allman Style、1TBS。

示例:

1
2
3
4
5
6
7
8
9
// K&R
- (void)functionExample
{
if (YES){
...
} else {
...
}
}
1
2
3
4
5
6
7
8
9
10
11
12
// Allman Style
- (void)functionExample
{
if (YES)
{
...
}
else
{
...
}
}

主要注意点:

a. 对于函数

开括号应在下一行中独占一行,并与开头行有相同的缩进。括号内的语句应该缩进。闭括号应单独占一行,并与开头行有相同的缩进。

b. 对于函数内的控制语句块

(K&R, 1TBS)开括号应与控制语句在同一行中,闭括号单独占一行(除非有 else 或 while 关键字),并与开头行有相同的缩进。<br /> 
(Allman Style)与函数一致,开括号也应独占一行。

c. 如果控制语句块内只有一条语句

(1TBS)不能省略括号。<br />
(K&R)可以省略括号(强烈不推荐,很容易产生逻辑错误,如著名的苹果 gotofail bug)。<br />

(2)不允许 的大括号缩进方式

a.闭括号不独占一行

1
2
- (void)functionExample{
if (YES){...}}

b.括号层次对应关系不正确

1
2
3
4
5
6
7
- (void)functionExample
{
if (YES)
{
...
}
}

自动化工具

  1. 简单地调整代码缩进,可运用 Xcode 的 Re-Indent,快捷键 ⌃I。
  2. 更复杂地调整代码格式,可使用 Uncrustify 等工具进行自动化调整。

注释规范

注释范围及内容

  1. 对于每一个类,必须 在头文件中为其添加类注释。
  2. 对于类的公有属性,必须 在头文件中为其添加属性注释。
  3. 对于类的公有方法,必须 在头文件中为其添加方法注释。
  4. 对于不含有任何类的头文件,必须 在头文件中为其添加头文件注释。
  5. 对于周知的方法,如常用控件的代理方法、SDK 中提供的方法等,不必添加注释(除非必要)。
  6. 对于需要暂时屏蔽的代码(段),可通过注释的形式进行屏蔽。
  7. 对于确定无用或已废弃的代码(段),不应以注释的形式存在于工程中。

注意事项

  1. 注释要用正确、清晰、符合语法的中文或英文书写。
  2. 注释怕短不怕长。注释要详尽地反映代码(段)的业务意义或逻辑意义。
  3. 注释不是对语法的解释,千万不要写这种注释,这种注释是无效且无用的:
1
2
// 将x加一
x = x+1;

一般注释形式

  • 单行注释
1
2
// 注释内容
sum=a+b;

通常,超过 5 行的注释不应采用单行注释,应采用多行注释。

  • 多行注释
1
2
3
4
/*
注释内容1
注释内容2
*/

1
2
3
4
/*
* 注释内容1
* 注释内容2
*/
  • 较长代码段的注释
1
2
3
4
5
// Start: 代码段简介
firstLine;
...
lastLine;
// End: 代码段简介

关键注释形式

按照 HeaderDoc 标签规范书写。

  • 类注释
1
2
3
4
5
/*!
* 类描述
*/
@interface ExampleClass : NSObject {
}
1
2
3
/// 类描述
@interface ExampleClass : NSObject {
}
  • 属性注释
1
2
3
4
5
/*!
* @brief 属性简介
* @discussion 属性详细描述
*/
@property (strong, nonatomic) NSString *strExample;
1
2
/// 属性简介
@property (strong, nonatomic) NSString *strExample;

其中,@discussion 标签为可选项。

  • 方法注释

简单方法:

1
2
3
4
/*!
* @brief 方法简介
*/
- (void)simpleMethod;
1
2
/// 方法简介
- (void)simpleMethod;

含有参数和返回值的方法:

1
2
3
4
5
6
7
8
9
/*!
* @brief 方法简介
*
* @param para1 参数一描述
* @param para2 参数二描述
*
* @return 返回结果描述
*/
- (BOOL)exampleMethodWithPara:(NSString*)para1 anotherPara:(NSString*)para2;

更为复杂的方式:

1
2
3
4
5
6
7
8
9
/*!
* @brief 方法简介
* @discussion 方法具体描述
* @param para1 参数一描述
* @param para2 参数二描述
* @return 返回结果描述
* @warning 注意事项
*/
- (BOOL)exampleMethodWithPara:(NSString*)para1 anotherPara:(NSString*)para2;
  • 头文件注释
1
2
3
4
5
/*!
* @header Const.h
* @brief 常量表
* @author 编写人
*/
  • 枚举类型注释
1
2
3
4
5
6
7
8
9
10
11
12
/*!
* @typedef FruitType
* @brief 枚举类型简介
* @constant FruitTypeApple FruitTypeApple简介
* @constant FruitTypeBanana FruitTypeBanana简介
*/
typedef NS_ENUM(NSInteger, FruitType){
/// FruitTypeApple简介
FruitTypeApple,
/// FruitTypeBanana简介
FruitTypeBanana
};

自动化工具

VVDocumenter-Xcode,可方便地添加符合规范的注释。

注意事项

  • NSLog 语句输出的内容应有意义。

  • NSLog 语句只能出现在 Debug Target,在 Release Target 不应存在任何不必要的 NSLog 语句。可使用预编译宏来进行控制:

1
2
3
#if DEBUG
NSLog(@"something");
#endif
  • 工程应采用 ARC,并采用 strong 和 weak 替代传统的 retain, copy, assign。

  • 代码应松紧适度,适当运用空行。避免过度紧凑和过度宽松的代码,如:

过度紧凑的代码:

1
2
3
4
5
6
task1Step1;
task1Step2;
task1Step3;
task2Step1;
task2Step2;
task2Step3;
1
2
3
4
5
6
- (void)functionA
{
}
- (void)functionB
{
}

过度宽松的代码:

1
2
3
4
5
6
7
8
9
10
11
task1Step1;
task1Step2;
task1Step3;
task2Step1;
task2Step2;
task2Step3;

松紧适度的代码:

1
2
3
4
5
6
7
8
9
// Task1
task1Step1;
task1Step2;
task1Step3;
// Task2
task2Step1;
task2Step2;
task2Step3;
  • 应使用多条简单的代码,避免使用单条复杂的代码,以提高代码可读性。如应避免这样的代码:
1
2
3
4
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return (section == 0)?55:(section==2?30:20);
}

应更改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (section == 0)
{
return 55;
}
else if (section == 2)
{
return 30;
}
else
{
return 20;
}
}
  • 应避免在循环体中处理边界,如
1
2
3
4
5
6
7
8
for (int i=0;i<10;i++)
{
if (i==0)
{
...
}
...
}
  • 对于参数很多的函数,参数各占一行,并以冒号对齐,如:
1
2
3
4
5
6
7
- (void)exampleFunctionWithPara:(int)para1
anotherPara:(int)para2
theThirdPara:(int)para3
theFourthPara:(int)para4
{
...
}
1
2
3
4
5
[self exampleFunctionWithPara:1
anotherPara:2
theThirdPara:3
theFourthPara:4
theFifthPara:5];