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 <UIKit/UIKit.h>
  ```
  • 头文件包涵(#import)之间,如果需要分类区别,各类别之间空1行

      #import <AFNetworking.h>
      #import <UIKit+AFNetworking.h>
          
      #import <MJRefresh.h>
    
  • 头文件包涵(#import)与@class之间空1行

    #import <MJRefresh.h>
    
    @class CenterViewController;
    
  • {} 外空1行,书写属性,如果需要分类区别,各类别之间空1行

  • 空1行开始写方法,如果需要分类区别,各类别之间空1行

  • 方法完成后,空1行 @end

#import <UIKit/UIkit.h>
#import <Foundation/Foundation.h>

#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 <NSObject>

  @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` 弱引用,以避免循环引用。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容

  • iOS编程规范0规范 0.1前言 为􏰀高产品代码质量,指导广大软件开发人员编写出简洁、可维护、可靠、可 测试、高效...
    iOS行者阅读 4,418评论 21 35
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,068评论 1 32
  • 推荐文章:禅与 Objective-C 编程艺 前言 为􏰀高产品代码质量,指导广大软件开发人员编写出简洁、可维护、...
    WolfTin阅读 2,739评论 0 1
  • 代码格式 使用空格而不是制表符 Tab 不要在工程里使用 Tab 键,使用空格来进行缩进。在 Xcode > Pr...
    small_Sun阅读 1,342评论 1 3
  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,258评论 8 265