iOS代码编程规范-按照项目经验汇总

带出几十位从零初叶学iOS的实习生或试用期的开发人员后,觉得实在是千人千面,每个人写的代码都风格暗淡无光,若是没有一个文档规范,每趟都和新人举办口头的说法,几乎自己是毫不敲代码了,所以吃了亏了就起来编制iOS的编程规范。由于自家在写iOS代码前一直是C语言的开销,所以广大业内都受C语言的熏陶。

编程规范.png

与大家分享下自己计算的编程规范,有不适于的请我们提议(最好能举例表达为什么糟糕,并给一个好的推荐\_

1. 率领标准

(1)首先是为人编写程序,其次才是电脑。

软件的生命周期贯穿产品的支付,测试,生产,用户采用,版本升级和中期维护等经过,唯有易读,易维护的软件代码才有所生命力。

(2)保持代码的领会清晰,幸免超负荷的编程技巧。

大致是最美。不要过分追求技术,否则会减低程序的可读性。

(3)编程时首先达到科学,其次考虑功用。

编程首先考虑的是满足正确性,健壮性,可维护性,可移植性等质量因素。

(4)编写代码时索要考虑到代码的可测试性。

不可以测试的代码是心有余而力不足保全质量的。完结设计作用的还要,要提供能够测试、验证的主意。

(5)函数(方法)是为一一定功效而编写,不是万能工具箱。

办法是一个处理单元,是由特定功用的,所以应该很好地安顿格局,无法是兼备东西都位于一个艺术里心想事成。

(6)鼓励多注释。

当代码有转移时,注释一定要修改,并且永不添加多余或另行的笺注。

2. 布局

次第布局的目标是有血有肉出程序可以的逻辑结构,进步程序的准头、一连性、可读性、可维护性。统一的先后布局和编程风格,有助于增长总体项目标支付质量,进步开发成效,下跌开发花费。

按照统一的布局顺序书写头文件和贯彻公文:

文件头注释
#import
文本之中选拔的宏
常量定义
文件之中选用的数据类型
全局变量
地点变量
类定义/实现

(1)If、else、else if、for、while、do等语句自占一行,执行语句不得紧跟其后,不论执行语句有微微都要加{}。

“{”前边添加一个空格,紧跟语句后。方法(函数)时,“{”另起一行并独
占一大篆写。

if ( numberA > numberB ) {
    return numberA;
}

(2)定义指针类型的变量,“*****” 应该置身变量前。

NSString *str1 = @"Hello World!";

(3)源代码中涉嫌相比紧密的代码应尽可能相邻。

CGFloat fWidth;
CGFloat fLength;
CGFloat fHeight;

(4)禁止利用TAB键,必须采纳空格进行缩进,缩进为4个空格。

在Xcode->Preferences->Text Editing->Indentation->Prefer
indent using中,将值设置为Spaces。

(5)程序的交界符“{”和“}”在if、else、else if、for、while、do等说话时,“{”前添加空格紧跟语句后。在点子(函数)应垄断一行并且位居同一列,同时与引用他们的言语对齐。“{}”之内的代码块使用缩进规则对齐。

- (void)dealloc
{
    // Do Something
}

if (isUpdated) {
        // Do Something
}

(6)相关的赋值语句等号对齐。

promotionsEntity.promotionImageStr   = activityItemDict[@"promotion_image"];
promotionsEntity.promotionIdNum      = activityItemDict[@"promotion_id"];
promotionsEntity.promotionNameStr    = activityItemDict[@"promotion_name"];
promotionsEntity.promotionColorStr   = activityItemDict[@"promotion_color"];

(7)在switch语句中,每一个case分支和default要用“{}”括起来,“{}”中的内容须要缩进。

(8)函数(方法)块之间拔取一个空行分隔。

(9)一元操作符如!、~、++、–、*、&、和[]、.、->、前后不加空格。

!bValue
~iValue
++iCount
*strSource
&fSum

(10)多元运算符和她俩的操作数之间起码须求一个空格。

fWidth = 5 + 5;
fLength = fWidth * 2;
fHeight = fWidth + fLength;

(11)关键字之后要留空格。“(”后和“)”前 不添加空格。

if、for、while等要害字之后应留一个空格再跟左括号”(”。

if (0 == fWidth)

(12)方法名与形参不可能留空格,再次来到类型与措施标识符有一个空格。

方法名后紧跟”:”,然后紧跟形参,重返类型”(”与”-”之间有一个空格。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

(13)注释符与注释内容之间要用一个空格举办剪切。

/* 设置Frame的值 */
// TO DO

(14)长表明式(当先80列)要在低优先级操作符处拆分成新行,操作符放在新行之首(以便卓绝操作符)。拆分出的新行要开展恰当地缩进,使排版整齐。

if ( 0 == fWidth
    || 0 < fLength )

(15)函数(方法)声明时,类型与名称差别意分黑体写。

- (void)didReceiveMemoryWarning

(16)类中功效模块以#pragma mark – 分割,上空两行,下空一行

#pragma mark – UITextFieldDelegate

(17)方法完毕时,参数过长则每个参数用一行,以冒号对齐。

- (void)doSomethingWith:(NSString *)theFoo
                   rect:(CGRect)theRect
               interval:(CGFloat)theInterval
{

比方措施名比参数名短,则每个参数占用一行,至少缩进4个字符,且为垂直对齐(非冒号对齐)。

- (void)short:(NSString *)theFoot
    longKeyword:(CGRect)theRect
    evenLongerkeyword:(float)theInterval
{
}

(18)方法调用沿用表明方法的习惯。

在同一行

[self doSomethingWith:@"test" rect:self.view.frame interval:1.0f];

或 冒号对齐

[self doSomethingWith:@"test"
                 rect:self.view.frame
             interval:1.0f];

(19)@public 和 @private 使用单独一行,且缩进1个字符

(20)Protocals申明中项目的识符、代理名称、尖括号间不留空格。

id<MyProtocalDelegate> delegate;

在类声明中隐含多个protocal,每个protocal占用一行,缩进2个字符。

@interface CustomBackButtonViewController () <UITextFieldDelegate,
  MyProtocalDelegate,
  UITabBarControllerDelegate,
  UITabBarDelegate>

C语言,也足以与第四个对齐,保持清晰易读

@interface ShopViewController () <UIGestureRecognizerDelegate,
                                  HXSClickEventDelegate,
                                  UITableViewDelegate,
                                  UITableViewDataSource>

一经不用所有办法都是必须得,使用@optional标示。

(21)UIViewController.m的文书布局,不一致变量和方法的先后顺序:

<1>#import “LocationCustomButton.h”

最开首是导入需求选择到的别样class头文件,头文件按类型分类

// controller
#import “TextSelectionViewController.h"
// model
#import "PayPasswordUpdateModel.h"
#import "WalletModel.h"
// views
#import "PayPasswordAlertView.h"
<2>#define KEY_BANK_TAIL @“bank_tail"

添加宏定义,将在文书中须求使用到的常量,字符串等用宏定义。

<3>@property (nonatomic, strong) NSArray *bankCardList;

property的特性定义。不用将须求运用的methods声明,在iOS7后Methods已经不要求先申明再采用了。

<4>- (void)viewDidLoad

#pragma mark - Life Cycle 添加生命周期的章程

- (void)viewWillAppear:(BOOL)animated
 - (void)viewDidAppear:(BOOL)animated
- (void)viewWillDisappear:(BOOL)animated
-(void)viewDidDisappear:(BOOL)animated
- (void)didReceiveMemoryWarning
- (void)dealloc
<5>#pragma mark - override

重载父类的措施

<6>#pragma mark - Intial Methods

开端化的艺术,如

- (void)initialNavigationBar
- (void)initialTableView
<7>#pragma mark - Target Methods

点击事件或通知事件

<8>#pragma mark - UITextFieldDelegate

Delegate的风浪,将所有的delegate放在同一个pragma下

<9>#pragma mark - Setter Getter Methods

抱有的property使用懒加载,并将setter或getter放在尾部,不影响工作代码的读书。

<10>#pragma mark - private method

民用方法的代码尽量抽取成立公共class。

3. 注释

(1)多行注释选择”/* … */”, 单行注释选取 “// …”.

(2)一般情状下,源程序有效注释量必须在30%上述。

诠释语言不宜太多也不可以太少,注释语言必须规范、易懂、简洁。

(3)注释应与其讲述的代码相近,对代码的注明应放在其上方或右手相邻地方,不可放在下方,如放于上方则须要与其上边的代码用空行隔开。

(4)注释与所讲述内容开展相同地缩排。

(5)文件最前方的注释,是保存了工程自动生成的注释,不过急需进行如下修改:文件小编改为私有的名字,公司名为Insigma Hengtian software Ltd. 如:

//
//  ViewController.m
//  test
//
//  Created by ArthurWang on 14-5-7.
//  Copyright (c) 2014年 Insigma HengTian Software Ltd. All rights reserved.
//

(6)类、协议、结构体注释。如:

/*
 @class HTServerDatamanager
 @abstract 异步连接服务器管理类
 @discussion 异步请求服务器,接收到响应后,通过回调把数据回传到对象
 */

(7)成员方法、接口注释。如:

/*
 @method  initWithTarget:selector:
 @abstract  类初始化函数
 @discussion  本类使用时必须调用此函数进行初始化
 @param target 响应回调对象
 @param selector  回调对象的selector
 @result   类对象
 */

4. 命名

(1)标识符要采纳英文单词或其构成,便于记念和读书,切忌选取普通话拼音来定名。

标识符应当直观且可以拼读,可望文知意,英文单词一般不要太复杂,用词应当规范。

(2)严峻禁止行使一而再的下划线,下划线也无法冒出在标识符头或最终。(实例变量及特殊用法除外)

CGFloat variable__name;
NSString *variale___name;

(3)程序中并非出现仅靠大小区其他一般的标识符。

NSString *contentOfView;
NSString *ContentOfView;

(4)宏、常量名都要动用大写字母,用下划线‘_’分割单词。

#define URL_GAIN_QUOTE_LIST @"/v1/quote/list"
#define URL_UPDATE_QUOTE_LIST @"/v1/quote/update"
#define URL_LOGIN   @"/v1/user/login”

(5)程序中有的变量不要与全局变量重名。

尽管有些变量和全局变量的效能域分化而不会发生语法错误,但简单使人误会。

(6)使用同一的前缀来分别变量的成效域。

g_ 全局变量
s_ 模块内静态变量

(7)方法名用小写字母初阶的单词组合而成。

艺术名力求清晰、明了、通过艺术名就可见看清方法的首要性意义。方法名中分裂含义字段之间并非用下划线连接,而要把种种字段的首字母大写以示区分。

- (NSString *)descriptionWithLocale:(id)locale;

(8)尽量防止名字中冒出数字编号,如Value1, Vlaue2等,除非逻辑上实在要求编号。

(9)注脚实例变量,都选用property。

不在类申明和兑现的“{”与“}”之间讲明。

@interface LumberjackViewController ()
{
    NSArray *dataSource;  // 错误:
}

(10)类名(及其category 和protocal)的首字母大写,使用假名大写的样式分开单词。

5. 变量

变量、常量和数据类型是先后编制的底子,是一贯关联到程序设计的成败。

(1)一个变量有且唯有一个职能,尽量不要把一个变量用作二种用处。

一个变量只用来表示一个一定效能,不要把一个变量作四种用途。

(2)循环语句与判断语句中,不容许对其余变量举办测算与赋值。

错误: if ( 100 > (fWidth = 50 * fLength) )

(3)宏定义中倘诺带有表明式或变量,表明式和变量必须用小括号括起来。

#define MY_MIN(A, B)   ((A)>(B)?(B):(A))

(4)宏名大写字母

(5)对于全局变量通过统一的函数访问。

(6)最好不要在语句块内注解局地变量。

(7)系统常用类作实例变量表明时进入后缀:

UIViewController: VC                      UIImage: Img
UIImageView:ImagView                   UIView:View
UILabel: Lbl                                    UIButton:Btn
UINavigationBar:Nbar                     UIToolbar:Tbar
UISearchBar:Sbar                            UITextField:TextField
UITextView:TextView                      NSArray:Array
NSMutableArray:Marray                  NSDictionary:Dict
NSMutableDictionary:Mdict             NSString:Str
NSMutableString:MStr                     NSSet:Set
NSMutableSet:Mset

(8)属性申明严把权力,对不须求外部修改的习性使用readonly。

(9)NSString使用copy而非retain。

在ARC中NSString的使用Strong与Copy的听从等同。

(10)CFType 使用@dynamic,禁止行使@synthesize

(11)除非必须,使用nonatomic。

(12)定义NSArray和NSDictionary使用泛型,进步代码可读性和健壮性。

NSArray<NSString *> *testArr = [NSArray arrayWithObjects:@"Hello", @"world", nil];
NSDictionary<NSString *, NSNumber *> *dic = @{@"key":@(1), @"age":@(10)};

在* 符号前面都添加一空格。

6. 表达式

表明式是语句的一部分,他们是不可分割的。

(1)一条语句只完毕一个意义。

复杂的说话阅读起来,难于了然,并简单隐含错误。

(2)在表明式中运用括号,使表明式的运算顺序更显明。

是因为将运算符的优先级与结合律熟记是相比较困难的,为了预防暴发歧义并增强可读性,即便不加括号时运算顺序不会变动,也应该用括号确定表明式的操作顺序。

if ( (( 0 == iYear%4 ) && ( 0 != iYear%100 )) || ( 0 == iYear%400 ) )

(3)幸免表达式中的附加成效,不要编写太复杂的复合表达式。

错误:int iResult = iYear++-++iMonth+iDay++;

(4)不可将布尔变量和逻辑表明式直接与YES、NO或则1、0展开比较。

if (isSuccess)   //真
if (!isSuccess)  //假

(5)在基准判断语句中,当整型变量与0相比时,不可模仿布尔变量的作风,应当将整型变量用“==”或“!=”直接与0比较。

if (0 == iYear)
if ( 0 != iMonth )

(6)应当将指针变量用“==”或“!=”与nil比较。

指南针变量的零值是“空”(即nil),nil的值与0相同,可是两岸含义不一致。

if ( nil == strName )

(7)在switch语句中,每一个case分支必须运用break结尾,最终一个分层必须是default分支。

幸免漏掉break语句造成程序错误,同时保持程序简洁。对于多少个支行相同处理的图景能够共用一个break,不过要用注释加以阐明。

(8)不可在for循环内修改循环变量,幸免for循环失去控制。

(9)循环嵌套次数不当先3次。

(10)do while 语句和while语句仅使用一个标准。

(11)如若循环体内设有逻辑判断,并且循环次数很大,宜将逻辑判断移到循环体的外围。

(12)for语句的巡回控制变量的取值拔取“半开半闭区间”写法。

诸如此类做更能适应数组的风味,数组的下标属于一个“半开半闭区间”。

int iMax[1000];
for (int i = 0; i < 1000; i++)
{
    NSLog(@"%d", iMax[i]);
}

(13)将int值转换为BOOL时应越发小心。

(14)OC中,BOOL被定义为unsigned char,那意味除去YES(1)和NO(0)外它仍是可以是其他值。禁止将int间接转换为BOOL。

(15)将整型值转换为BOOL的法门:使用长富运算符再次回到YES/NO,或选取&&,||。

(16)BOOL、_BOOL和bool之间的转换是高枕无忧的,然则BOOL和Boolean间的转移不是安全的,所以将Boolean堪称整型值。

(17)在OC中,只允许行使BOOL。

7. 函数

(1)方法无法为多个目标服务。

一个艺术一个功效。

(2)在接口中应当尽量少使用外部定义的花色(裁减耦合)。

(3)幸免函数有太多的参数,参数个数尽量控制在5个以内。

假设参数的确相比多,不妨把这几个参数定义成一个构造(或一个类)。

(4)对于有重回值的函数(方法),每一个支行都无法不有再次回到值。

为了有限接济对被调用函数再次回到值的判定,有重回值的函数中都每一个退出点都亟需有再次回到值。

(5)对输入参数的不错和实用举行检讨。

过多先后不当和崩溃是由地下参数引起的。

(6)避免将函数(方法)的参数作为工作变量。

将函数的参数作为工作变量,有可能错误地转移参数内容。对必须改变的参数,最好先用局地变量代之,最终再将该部分变量的内容赋给该参数。

(7)函数(方法)体的范畴不能太大,尽量控制在200行以内。

没完没了的函数不便利调试,可读性差。

(8)禁止直接调用NSObject的类方法+new,也毫无在子类中重载它。使用alloc和init方法。

(9)创设对象时尽可能采纳autorelease,制造临时对象时,尽量同时在同一行中autorelease掉,而非使用单独的release语句。

(10)Dealloc的逐条要与变量表明的逐条相同。

那般有利于review代码。
一旦dealloc中调用其他方法来release变量,将被release的变量以注释的样式标注清楚。
先release自身成员变量,再调用父类dealloc方法。

8. 头文件

(1)表明成员类,应该引用该类评释,而不是含有该类的头文件。

@class MyViewController;
@interface ViewController : UIViewController
{
    MyViewController *_myViewController;
}

(2)共同的接口、结构体、常量和数据类型要定义在同一个头文件里。

(3)使用#import引入OC和OC++头文件,使用#include引入c和c++头文件。

9. 可靠性

为有限支撑代码的可信赖性,编程时请遵守如下基本原则,优先级递减:
正确性
稳定性
可测试性
规范/可读性
全局功效
一对成效
民用表明形式/个人方便性

(1)避免内存操作越界

内存操作首假如指对数组、指针、内存地址等得操作,内存操作越界是软件系统关键错误之一,后果往往分外严重,引起崩溃。

(2)当变量释放后,必要将变量置为nil。

幸免因为野指针引起的顺序崩溃。

(3)变量在行使前应先导化,幸免未开首化的变量被引用。

引用未早先化的变量,会唤起程序的垮台。

(4)指针类型变量必须开端化为nil。

(5)指针不要举办复杂的逻辑或算术操作。

由此复杂的逻辑或算术操作后,指针的职位就很难确定。

(6)收缩指针和数据类型的强制类型转化。

强制类型转化如若类型强转错误会滋生崩溃。

(7)对变量举行赋值时,必须对其值举行合法性检查,防止越界等现象暴发。

(8)非开头化方法中的alloc操作以前务要求nil判断。

(9)在编制派生类的赋值时,主要不要忘记对基类的分子变量重新赋值。

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

(10)私有方法应该在落实文件中表明。

@interface ViewController ()
- (void)login;
@end

10. 断言

预感是对某种如若条件举行反省,可以很快发现并一定软件文件,同时对系统错误进行机动报警。

(1)整个软件系统应该选择统一的断言。

assert(str);

(2)正式软件出品中应把断言及其他的调测代码去掉。

加速软件运行速度。

11. 其他

(1) 防止过多直接行使即时数。

有道是都应用宏定义,采取即时数不便于领会含义并不难出错。

(2) 枚举首个分子要赋伊始值。

(3) addObject从前要非空判断。

(4) release版本代码去掉NSLog打印,除了保留万分分支的NSLog。

(5) 禁止在代码中直接写死字符串资源,必须求用字符串ID替代。

有道是考虑多语言国际化,尽量使用NSLocalizedStringFromTable完结对字符串ID的引用。

(6) 对于框架设计,逻辑层尽量与UI层分离,下跌耦合度。

(7) delegate对象使用assign,禁止选取retain。

因为retain会引起导致循环索率领致内存败露,并且对品种的内存走漏不可能被Instrument发现,极难调试。

(8) Controller独立于View和Controller。

绝不在View相关的类中添加过多的事体逻辑代码,那让代码的可重用性很差。Controller负责业务逻辑代码,且Controller的代码与View尽量无关。

(9)init方法和dealloc方法是最常用的不二法门,所以将她们放在类完毕的发端地点。

(10) 使用空格将同一的变量、属性对齐,使用换行分组。

// END

小结写完了,复制黏贴好累啊。发现许多条在付出中都从未有过遵循,因为需要变动实在太频仍了,并且必要的付出时间实在太短。吐槽下产品组,能仍然不能够多着想多着想然后听听我们开发的视角啊。!_!