iOS 代码规范文档
[toc]
修订
序号 | 版本 | 修订人 | 修订日期 | 备注 |
---|---|---|---|---|
1 | 1.0 | 李俊杰 | 2018-07-31 | 起草 |
2 |
概述
- 制定目的:制定iOS 编码规范,主要是为了规范公司内部的iOS 代码,提高代码可读性,降低沟通成本和学习成本。
- 必然性:随着iOS团队的人员数量不断增多,必须有一个规范来约束开发者,避免代码格式百花齐放导致项目维护、交接成本增加;同时,在多人开发项目中减少沟通成本,提升编码效率。
- 适用对象:iOS 开发人员, iOS 团队管理人员。
- 适用范围:适用公司所有用Objective-C语言开发的iOS项目。
文件及目录管理规范
-
项目创建完成开始编码时,必须遵从项目文件路径和物理文件路径对应;
例如:xcode目录中存在Class目录,在硬盘的物理文件中必须存在Class文件夹;xcode中Class目中的文件必须放到硬盘物理文件Class目录中;
每个项目有一个公用目录放公共资源,根据具体的需求,在公共资源文件夹下,建立对应的子类文件夹。
文件夹命名首字母必须大写,遵循驼峰拼写规则。em. Resources, ViewModels
-
图片资源
图片资源必须使用
icon_
开头,由英文字母、数字、“”组成。如果使用单词必须使用完整单词不允许使用简写;单词之间使用“”区分。em. icon_head,icon_feature_settings, icon_animation_ball1项目中没有特殊原因的话,所有图片必须放到:Images.xcassets中,Images中根据项目模块区分不同的目录,图片名称前加模块名称做为前缀,避免图片冲突。
不允许所有图片都放到Images的根目录下。
代码注释规范
注释可以采用’ /* / ’和’ // ’两种注释符号,涉及到多行注释时,尽量使用 ’ / */ ’。
对于一行代码的注释可放在前一行及本行上,不允许放在下一行,更不允许在一行语句的中间加入注释。
单元文件的文件头注释说明应按如下格式:
```
//
// AppDelegate.m //文件名
// UniXin // 项目名
//
// Created by JunJie on 2018/7/31. //创建人及日期
// Copyright © 2018年 Longfor Properties Co. Ltd. All rights reserved. //版权
//
- 方法前面的注释遵循以下格式:如果某项没有,不显示。公共接口的每个方法,都应该有注释来解释它的作用、参数、返回值以及其它影响(建议放到description中)。
```
/**
@description 根据轮子和车架创建一个汽车
@param 轮子
@param 车架
@return 一个汽车
*/
- (Car *)createCar:(NSString *)wheel carFrame:(NSString *)carFrame;
```
- 使用 | 来引用注释中的变量名及符号名而不是使用引号。这会避免二义性,尤其是当符号是一个常用词汇,这使用语句读起来很糟糕。例如,对于符号 count :
例如:
// Sometimes we need |count| to be less than zero.(有时候我们需要|数量|的值小于0)
- 不必每行都加注释,在关键代码处,5行代码左右处做注释;
- 协议及模块之间需要加#pragma marks - 来区分
## 编码排版格式规范
### 空行
#### .h文件中的空行
- 文件说明与头文件包涵(#import)之间空1行
//
// ViewController.h
// UniXin
//
// Created by JunJie on 2018/7/31.
// Copyright © 2018年 Longfor Properties Co. Ltd. All rights reserved.
//
#import
```
-
头文件包涵(#import)之间,如果需要分类区别,各类别之间空1行
#import
#import #import -
头文件包涵(#import)与@class之间空1行
#import
@class CenterViewController; {}
外空1行,书写属性,如果需要分类区别,各类别之间空1行空1行开始写方法,如果需要分类区别,各类别之间空1行
方法完成后,空1行
@end
#import
#import
#import "GODOtherClass.h"
#import "GODOtherModel.h"
@class GODAnotherClass;
@protocol GODAnotherProtocol;
@interface GODExample : NSObject {
NSString *instanceVariable;
}
@propety (nonatomic, strong) GODOtherModel *otherModel;
- (void)test;
@end
.m中的空行
- 文件说明与头文件包涵(
#import
)之间空1行 - 头文件包涵(
#import
)之间,如果需要分类区别,各类别之间空1行 -
@implementation
和@synthesize
之间空一行,@synthesize
不要使用逗号(,
)如果需要分类区别,各类别之间空1行 -
@synthesize
与方法之间空1行 - 各方法之间空1行
- 方法名后空1行开始写实现。
- 变量声明后空1行。如果分类区别,各类别之间空1行。
- 条件,循环,选择语句,整个语句结束需要空1行。
- 最后一个结束括号之前不空行。
- 注释与代码之间不空行。
-
#pragma mark -
与方法之间空1行。
#pragma mark - private methods
- (void)privateMethod1 {
NSString *innerVariable1 = nil;
NSInteger innerVariable2 = 100;
BOOL condition = YES;
if (condition) {
NSLog(@"xxxxx");
}
//do real logic
}
关于空格
- .h中成员声明时,类型与变量之间有至少1个空格。星号(
*
)靠近变量,不靠近类型。(部分习惯,所有变量可以以*
对齐,中间留空)保留 -
@property
后有1个空格,()
里面,逗号后有1个空格,括号外,先留1个空格,再声明属性 - 方法+,-后,与
()
之间有1个空格 - 返回类型与
*
之间有1个空格,方法参数中返回类型与*
之间有1个空格 - 多参数的方法,每一个参数后面都有1个空格
- 将编辑器设置为1个
TAB
= 4个字符缩进,每次缩进4个空格(系统默认的) - 使用
Block
时,内容四个空格缩进,^
后带有参数时,参数与{
之间有一个空格缩进 -
@public
和@private
访问修饰符应该以一个空格缩进。 - 异常部分,每个
@
标签应该有独立的一行,在@
与{}
之间需要有一个空格,@catch
与被捕捉到的异常对象的声明之间也要有一个空格。for
循环语句和{
也有一个空格。
关于BOOL值
- 不要用
if(obj==nil){}
,而用if(!obj){}
- 比较时把常量放前面可以避免错误,不要用
if(aIntValue==255){}
,而用if(255==aIntValue){}
,避免漏掉一个=
,而变成赋值 - 不要用
if(aBool==YES){}
,直接用if(aBool){}
- 声明
BOOL
类型属性的时候要以is
开头,并且重写getter
命名规范
保留字
Objective-c语言的保留字或关键词应全部使用小写字母,除下表中保留字外,private
、protected
、public
、在类型说明中也作为保留字使用。还有nonatomanic
,retain
,readwrite
, readonly
等也有特殊的使用场合。下表中的关键字不允许作为变量名使用。
_Bool | _Complex | _Imaginary | auto | break | bycopy |
---|---|---|---|---|---|
return | self | short` | restrict | typeof | union |
void | volatile | while | property | public | private |
byref | case | char | const | continue | default |
do | double | const | enum | extern | float |
for | got | if | in | inline | inout |
int | long | oneway | else | out | registre |
static | struct | super | switch | signed | sizeof |
文件
- 文件夹命名首字母必须大写,遵循驼峰拼写规则。em. Resources, ViewModels
方法
方法的名称应全部使用有意义的单词组成,且以小写字母开头,多单词组合时,后面的单词首字母大写(驼峰式书写)。 同时尽量让方法的命名读起来像一句话,能够传达出方法的意思。em. userName
-
设置类变量的内容的方法应使用
set
作为前缀,读取变量的内容的方法不应使用get
作为前缀。一般使用get
作为前缀,是需要改变传入引用的值。//错误方式 - (NSString *)getUsername; //正确方式 - (NSString *)username; - (void)getWidth:(CGFloat *)width fromSize:(CGSzie)viewSize;
-
方法中的参数:第一个参数名称要从函数名称上携带出来,第二个参数的首字母小写,多个单词组合时,后面单词首字母大写。参数有别名时,参数别名与前一参数保留1个空格。
- (instancetype)initWithUserName:(NSString *) cardId:(NSString *)cardId;
-
方法名称在同一类型操作的时候不要使用多个连续的介词(wtih、and)在多个参数之间连接。如果表示两个相对独立的操作,可以使用相关介词连接。
//错误 - (instancetype)initWithName:(NSString *)name withPassword:(NSString *)password; //正确 - (instancetype)initWithName:(NSString *)name password:(NSString *)password; //错误,不要使用"and"来阐明有多个参数 - (instancetype)initWithName:(CGFloat)width andAge:(CGFloat)height; //正确,使用"and"来表示两个相对独立的操作 - (BOOL)openFile:(NSString )fullPath withApplication:(NSString )appName andDeactivate:(BOOL)flag;
变量
-
变量必须起有意义的名字,使其他组员可以很容易读懂变量所代表的意义,变量命名可以采用同义的英文命名,可使用几个英文单词,第一个单词首字母小写,其他单词首字母大写。
//错误的命名 int w; int nerr; int nCompConns; tix = [[NSMutableArray alloc] init]; obj = [someObject object]; p = [network port]; //正确的命名 int numErrors; int numCompletedConnections; tickets = [[NSMutableArray alloc] init]; userInfo = [someObject object]; port = [network port];
对于一些特殊类型的变量,命名时要带上类型,如
NSArray
的变量命名为xxxArray,其他的如xxxDictionary,xxxSize等。这样就可以从名称上知道是什么类型的变量。千万不能将NSArray的变量命名为xxxDictionary。-
对于要和interface builder关联的的输出口变量,命名时要后缀以特定的控件名。
UILabel *userNameLabel; UIView *backgroundView;
本规则仅针对Objective-C代码,C++/C代码使用C++/C对应的习惯;
尽量避免使用全局变量,如果必须使用全局变量则必须加前缀 ‘static_’,同时应在变量名称中体现变量的类型。em. static_int_unreadNum,_static_NSString_appKey
私有实例变量前加一个下划线,如_dbPath。
枚举变量也要有相应的前缀来区分不同的
enum
变量。比如官方的一个enum
。
typedef enum CGPathDrawingMode CGPathDrawingMode;
/* Drawing modes for text. */
enum CGTextDrawingMode {
kCGTextFill,
kCGTextStroke,
kCGTextFillStroke,
kCGTextInvisible,
kCGTextFillClip,
kCGTextStrokeClip,
kCGTextFillStrokeClip,
kCGTextClip
};
常量
避免在程序中直接出现常数,使用超过一次的应以宏定义的形式来替代。
常数的宏定义应与它实际使用时的类型相一致。如以3.0来定义浮点类型,用3表示整型。
-
常量的命名应当能够表达出它的用途,常量名(如宏定义、枚举、静态局部变量等)应该以小写字母
k
开头,使用驼峰格式分隔单词,如:FOUNDATION_EXTERN MSString * const kGODExampleDidFinishedNotification; extern NSString * const kGODLoginDidFinishedNotification;
static NSString *kGODCustomerCellID = @"GODCustomerCellID";
define kGODCustomerCellHeight 200.f
- 一些常量前加特殊前缀,可以作为不同常量的区分
UserDefaultsKey 的变量前加UDKEY_,
NotificationNameKey 前面加NNKEY_,
DictionaryKey 前面加DICTKEY_,
### 属性
- 修饰符的顺序:nonatomic > strong/weak/retain/copy > readonly > getter/setter=
- NSString类型的属性使用copy进行修饰。
- Block类型的属性使用copy进行修饰。
- delegate类型的属性使用weak进行修饰,系统会在dealloc的时候自动设置成nil。以避免循环引用。
- 尽量避免使用原子性修饰,否则会因为同步操作产生额外的开销。默认的设置是原子的。
### 类
- 所有的类名,协议名(Protocol)均以大写字母开头,多单词组合时,后面的单词首字母大写。类、协议名必须是有意义的。
- 继承自UIView的类以View结尾。em. UserInformationView
- 继承自ViewController的类以viewController结尾。em. LoginViewController
- 所有保存数据的实体以Model结尾。em. userModel
- 分类(类别)命名:与类命名相同,此外需添加要扩展的类名和 `+`。 em. NSString+URLEncoding
- 协议(委托)命名:与类命名相同,此外需添加`protocol`后缀。 em. UINavigationControllerProtocol
@protocol GODExampleProtocol
@required
- (NSInteger)numberOfTableViewIndexPath:(NSIndexPath *)indexPath;
@optional
- (void)didSelectedIndexPath:(NSIndexPath *)indexPath;
@end
### 其他
- 每个方法不能超过100行,超过100行的代码必须拆分。
- 嵌套语句不能超过3层;超过3层必须优化和拆分。
- 每个类文件行数建议在500行左右,不能超过1000行,超过1000行必须考虑抽象类来重构代码。
- 代码行度最大为100列(C++的是80),可以在xcode的Text Editing中修改。
- 尽可能保证 .h文件的简洁性,可以不公开的API就不要公开了,写在实现文件中即可。
- 及时删除无用的注释和无用的代码。
- 代码中不应该出现控件的绝对坐标,应尽可能使用相对坐标。
- 写`delegate` 的时候类型应该为`weak` 弱引用,以避免循环引用。