iOS 代码规范文档

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语言的保留字或关键词应全部使用小写字母,除下表中保留字外,privateprotectedpublic 、在类型说明中也作为保留字使用。还有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` 弱引用,以避免循环引用。

你可能感兴趣的:(iOS 代码规范文档)