IOS-代码书写规范
2015-11-30 23:10
453 查看
前 言 1. 指导原则 2. 布局 2.1. 文件布局 2.2. 基本格式 2.3. 对齐 2.4. 空行空格 2.5. 断行 3. 注释 4. 命名规则 4.1. 基本规则 4.2. 资源命名 5. 变量,常量,宏与类型 5.1. 变量、常量以及宏 5.2. 类型 6. 表达式与语句 7. 函数、方法、接口 8. 头文件 9. 可靠性 9.1. 内存使用 9.2. 指针使用 9.3. 类 10. 断言与错误处理 11. 其它补充 12. 参考文档 1 前 言 本规范针对于iOS的object-c开发语言。 1. 指导原则
2. 布局程序布局的目的是显示出程序良好的逻辑结构,提高程序的准确性、连续性、可读性、可维护性。更重要的是,统一的程序布局和编程风格,有助于提高整个项目的开发质量,提高开发效率,降低开发成本。同时,对于普通程序员来说,养成良好的编程习惯有助于提高自己的编程水平,提高编程效率。因此,统一的、良好的程序布局和编程风格不仅仅是个人主观美学上的或是形式上的问题,而且会涉及到产品质量,涉及到个人编程能力的提高,必须引起大家重视。2.1.文件布局
头文件布局: 文件头(参见“注释”一节) #import (依次为标准库头文件、非标准库头文件) 全局宏 常量定义 全局数据类型 类定义 正例: /*************************************************************************** * 文件引用 ***************************************************************************/ /*************************************************************************** * 类引用 ***************************************************************************/ /*************************************************************************** * 宏定义 ***************************************************************************/ /*************************************************************************** * 常量 ***************************************************************************/ /*************************************************************************** * 类型定义 ***************************************************************************/ / *************************************************************************** * 类定义 ***************************************************************************/
实现文件布局: 文件头(参见“注释”一节) #import (依次为标准库头文件、非标准库头文件) 文件内部使用的宏 常量定义 文件内部使用的数据类型 全局变量 本地变量(即静态全局变量) 类的实现 正例: /*************************************************************************** * 文件引用 ***************************************************************************/ /*************************************************************************** * 宏定义 ***************************************************************************/ /*************************************************************************** * 常量 ***************************************************************************/ /*************************************************************************** * 类型定义 ***************************************************************************/ /*************************************************************************** * 全局变量 ***************************************************************************/ /*************************************************************************** * 原型 ***************************************************************************/ / *************************************************************************** * 类特性 ***************************************************************************/ @implementation ClassName @synthesize variableName; / *************************************************************************** * 类的实现 ***************************************************************************/
#import <stdio.h> #import “heads.h” 2.2.基本格式
正例: if (varible1 < varible2) { varible1 = varible2; } 反例:下面的代码执行语句紧跟if的条件之后,而且没有加{},违反规则。 if (varible1 < varible2) varible1 = varible2;
float *pfBuffer; 反例: float* pfBuffer;
正例: iLength = 10; iWidth = 5; // 矩形的长与宽关系较密切,放在一起。 StrCaption = “Test”; 反例: iLength = 10; strCaption = “Test”; iWidth = 5; 2.3.对齐
do while语句和结构的类型化时可以例外,while条件和结构名可与 } 在同一行。 正例: (void)Function:(int)iVar { // 独占一行并与引用语句左对齐。 while (condition) { doSomething(); // 与{ }缩进4格 } } 反例: void Function(int iVar){ while (condition){ DoSomething(); }}
int aiNumbers[4][3] = { 1, 1, 1, 2, 4, 8, 3, 9, 27, 4, 16, 64 }
tPDBRes.wHead = 0; tPDBRes.wTail = wMaxNumOfPDB - 1; tPDBRes.wFree = wMaxNumOfPDB; tPDBRes.wAddress = wPDBAddr; tPDBRes.wSize = wPDBSize;
正例: switch (iCode) { case 1: { DoSomething(); // 缩进4格 break; } case 2: { // 每一个case分支和default要用{}括起来 DoOtherThing(); break; } … // 其它case分支 default: { DoNothing(); break; } } 2.4.空行空格
正例: (void)hey { [hey实现代码] } // 空一行 // 空一行 (void)ack { [ack实现代码] } 反例: void Foo::Hey(void) { [Hey实现代码] } void Foo::Ack(void) { [Ack实现代码] } // 两个函数的实现是两个逻辑程序块,应该用空行加以分隔。
!bValue ~iValue ++iCount *strSource &fSum aiNumber[i] = 5; tBox.dWidth tBox->dWidth
fValue = fOldValue; fTotal + fValue iNumber += 2;
正例: -凵(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations. return (interfaceOrientation == UIInterfaceOrientationPortrait); }
例子中的 凵 代表空格。 for凵(i凵=凵0;凵i凵<凵MAX_BSC_NUM;凵i++) { DoSomething(iWidth,凵iHeight); }
/* 注释内容 */ // 注释内容 反例: /*注释内容*/ //注释内容 2.5.断行
for循环语句的续行在初始化条件语句处对齐。 函数调用和函数声明的续行在第一个参数处对齐。 赋值语句的续行应在赋值号处对齐。 正例: if ((iFormat == CH_A_Format_M) && (iOfficeType == CH_BSC_M)) // 条件表达式的续行在第一个条件处对齐 { doSomething(); } for (long_initialization_statement; long_condiction_statement; // for循环语句续行在初始化条件语句处对齐 long_update_statement) { doSomething(); } // 函数声明的续行在第一个参数处对齐 BYTE ReportStatusCheckPara(HWND hWnd, BYTE ucCallNo, BYTE ucStatusReportNo); // 赋值语句的续行应在赋值号处对齐 fTotalBill = fTotalBill + faCustomerPurchases[iID] + fSalesTax(faCustomerPurchases[iID]);
extern double FAR CalcArea(double dWidth, double dHeight); 反例: extern double FAR CalcArea(double dWidth, double dHeight); 3. 注释注释有助于理解代码,有效的注释是指在代码的功能、意图层次上进行注释,提供有用、额外的信息,而不是代码表面意义的简单重复。
正例: 下面是文件头部的中文注释: /********************************************************************* * 版权所有 (C)2011中兴软件技术(南昌)有限公司 * * 文件名称: // 文件名 * 文件标识: // 见配置管理计划书 * 内容摘要: // 简要描述本文件的内容,包括主要模块、函数及其功能的说明 * 其它说明: // 其它内容的说明 * 当前版本: // 输入当前版本 * 作 者: // 输入作者名字及单位 * 完成日期: // 输入完成日期,例:2011年11月29日 * 修改记录1:// 修改历史记录,包括修改日期、修改者及修改内容 * 修改日期: * 版 本 号://或版本号 * 修 改 人: * 修改内容://修改原因以及修改内容说明 * 修改记录2:… **********************************************************************/
正例: /*********************************************************************** * 方法名称: // 方法名称 * 功能描述: // 方法功能、性能等的描述 * 输入参数: // 输入参数说明,包括每个参数的作用、取值说明及参数间关系 * 输出参数: // 对输出参数的说明。 * 返 回 值: // 方法返回值的说明 * 其它说明: // 其它说明 ***********************************************************************/
正例: 如下书写比较结构清晰 /* 获得子系统索引 */ iSubSysIndex = aData[iIndex].iSysIndex; /* 代码段1注释 */ [ 代码段1 ] /* 代码段2注释 */ [ 代码段2 ] 反例1: 如下例子注释与描述的代码相隔太远。 /* 获得子系统索引 */ iSubSysIndex = aData[iIndex].iSysIndex; 反例2: 如下例子注释不应放在所描述的代码下面。 iSubSysIndex = aData[iIndex].iSysIndex; /* 获得子系统索引 */ 反例3: 如下例子,显得代码与注释过于紧凑。 /* 代码段1注释 */ [ 代码段1 ] /* 代码段2注释 */ [ 代码段2 ]
/* * 变量作用说明 * 变量值说明 */ BYTE g_ucTranErrorCode;
正例: 如下注释结构比较清晰 - (int)doSomething { /* 代码段1注释 */ [ 代码段1 ] /* 代码段2注释 */ [ 代码段2 ] } 反例: 如下例子,排版不整齐,阅读不方便; int DoSomething(void) { /* 代码段1注释 */ [ 代码段1 ] /* 代码段2注释 */ [ 代码段2 ] }
4. 命名规则4.1.基本规则好的命名规则能极大地增加可读性和可维护性。同时,对于一个有上百个人共同完成的大项目来说,统一命名约定也是一项必不可少的内容。本章对程序中的所有标识符(包括变量名、常量名、函数名、类名、结构名、宏定义等)的命名做出约定。
g_ : 全局变量 s_ : 模块内静态变量 空 : 局部变量不加范围前缀
整型 n 指针 p 字符串 str 布尔 b 字符 c 函数 fn 正例: @interface CMainMenu { int m_nWidth; NString *m_strName; BOOL m_bCheck; }
4.2.资源命名● 字符串:以“IDS_”开头,如:IDS_VIEW● 图片:以“IDB_”开头,如:IDB_COREICON 5. 变量,常量,宏与类型变量、常量和数据类型是程序编写的基础,它们的正确使用直接关系到程序设计的成败,变量包括全局变量、局部变量和静态变量,常量包括数据常量和指针常量,类型包括系统的数据类型和自定义数据类型。本章主要说明变量、常量与类型使用时必须遵循的规则和一些需注意的建议,关于它们的命名,参见命名规则。5.1.变量、常量以及宏
正例: do { [处理语句] cInput = GetChar(); } while (cInput == 0); 反例: do { [处理语句] } while (cInput = GetChar());
正例: #define HANDLE(A, B) (( A ) / ( B )) 反例: #define HANDLE(A, B) (A / B)
#define BUTTON_WIDTH (int)320 反例: #define kButtonWidth (int)320
正例: #define BUTTON_WIDTH (int)320 反例: #define BUTTON_WIDTH 320
正例: T_Student g_tStudent; T_Student GetStudentValue(void) { T_Student tStudentValue; [获取g_tStudent的访问权] tStudentValue = g_tStudent; [释放g_tStudent的访问权] return tStudentValue; } BYTE SetStudentValue(const T_Student *ptStudentValue) { BYTE ucIfSuccess; ucIfSuccess = 0; [获取g_tStudent的访问权] g_tStudent = *ptStudentValue ; [释放g_tStudent的访问权] return ucIfSuccess; }
5.2.类型
正例: typedef struct TeacherStruct { BYTE aucName[8]; BYTE ucSex; }T_Teacher; typedef struct StudentStruct { BYTE ucName[8]; BYTE ucAge; BYTE ucSex; WORD wTeacherInd; }T_Student; 反例: 如下结构不太清晰、合理。 typedef struct StudentStruct { BYTE aucName[8]; BYTE ucAge; BYTE ucSex; BYTE aucTeacherName[8]; BYTE ucTeacherSex; }T_Student;
正例:如下形式,不仅可节省字节空间,可读性也变好了。 typedef struct ExampleStruct { BYTE ucValid; BYTE ucSetFlg; BYTE ucOther; // 保留位 T_Person tPerson; }T_Example; 反例:如下结构中的位域排列,将占较大空间,可读性也稍差。 typedef struct ExampleStruct { BYTE ucValid: 1; T_Person tPerson; BYTE ucSetFlg: 1; } T_Example; 6. 表达式与语句表达式是语句的一部分,它们是不可分割的。表达式和语句虽然看起来比较简单,但使用时隐患比较多。本章归纳了正确使用表达式和if、for、while、goto、switch等基本语句的一些规则与建议。
正例: int iHelp; int iBase; int iResult; iHelp = iBase; iResult = iHelp + GetValue(&iBase); 反例: int iBase, iResult; // 一行定义多个变量 iResult = iBase + GetValue(&iBase); // 一条语句实现多个功能,iBase有两种用途。
正例: if (((iYear % 4 == 0) && (iYear % 100 != 0)) || (iYear % 400 == 0)) 反例: if (iYear % 4 == 0 && iYear % 100 != 0 || iYear % 400 == 0)
正例 : aiVar[1] = aiVar[2] + aiVar[3]; aiVar[4]++; iResult = aiVar[1] + aiVar[4]; aiVar[3]++; 反例: iResult = (aiVar[1] = aiVar[2] + aiVar[3]++) + ++aiVar[4] ;
正例: 设bFlag 是布尔类型的变量 if (bFlag) // 表示flag为真 if (!bFlag) // 表示flag为假 反例: 设bFlag 是布尔类型的变量 if (bFlag == TRUE) if (bFlag == 1) if (bFlag == FALSE) if (bFlag == 0)
if (iValue == 0) if (iValue != 0) 反例: if (iValue) // 会让人误解 iValue是布尔变量 if (!iValue)
正例: if ((fResult >= -EPSINON) && (fResult <= EPSINON)) 反例: if (fResult == 0.0) // 隐含错误的比较 其中EPSINON是允许的误差(即精度)。
正例: if (pHead == nil) // pHead与NULL显式比较,强调pHead是指针变量 if (pHead != nil) 反例: if (pHead == 0) // 容易让人误解pHead是整型变量 if (pHead != 0) 或者 if (pHead) // 容易让人误解pHead是布尔变量 if (!pHead)
对于多个分支相同处理的情况可以共用一个break,但是要用注释加以说明。 正例: switch (iMessage) { case SPAN_ON: { [处理语句] break; } case SPAN_OFF: { [处理语句] break; } default: { [处理语句] break; } }
正例: BOOL bCondition; do { …….. bCondition = ((tAp[iPortNo].bStateAcpActivity != PASSIVE) || (tAp[iPortNo].bStateLacpActivity != PASSIVE)) && (abLacpEnabled[iPortNo]) && (abPortEenabled[iPortNo]) } while (bCondition);
const int NUM = 100000; 正例: if (bCondition) { for (i = 0; i < NUM; i++) { doSomething(); } } else { for (i = 0; i < NUM; i++) { doOtherthing(); } } 反例: for (i = 0; i < NUM; i++) { if (bCondition) { DoSomething(); } else { DoOtherthing(); } }
正例: int aiScore[NUM]; … for (i = 0; i < NUM; i++) { printf(“%d\n”,aiScore[i]) } 反例: int aiScore[NUM]; … for (i = 0; i <= NUM-1; i++) { printf(“%d\n”,aiScore[i]); } 相比之下,正例的写法更加直观,尽管两者的功能是相同的。 7. 函数、方法、接口
- (BOOL)sio_set_baud_rate:(int)arg; - (BOOL)sio_set_stop_bits(byte)arg; - (BOOL)sio_set_data_bits(byte)arg; - (BOOL)sio_get_baud_rate:(int *)arg; 反例: - (BOOL)sio_ ioctl:(void *)arg;
8. 头文件
@class SubClassName; @interface ClassName : NSObject { SubClassName *m_pSubClassName; } 反例: #import “SubClassName.h”; @interface ClassName : NSObject { SubClassName *m_pSubClassName; } 9. 可靠性为保证代码的可靠性,编程时请遵循如下基本原则,优先级递减:● 正确性,指程序要实现设计要求的功能。 ● 稳定性、安全性,指程序稳定、可靠、安全。 ● 可测试性,指程序要方便测试。 ● 规范/可读性,指程序书写风格、命名规则等要符合规范。 ● 全局效率,指软件系统的整体效率。 ● 局部效率,指某个模块/子模块/函数的本身效率。 ● 个人表达方式/个人方便性,指个人编程习惯。 9.1.内存使用
正例: const int MAX_USE_NUM = 10 // 用户号为1-10 unsigned char aucLoginFlg[MAX_USR_NUM + 1]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - (void)ArrayFunction { unsigned char ucUserNo; for (ucUserNo = 0; ucUserNo < MAX_USE_NUM; ucUserNo++) { aucLoginFlg[ucUser_No] = ucUserNo; … … } } 反例: const int MAX_USE_NUM = 10 // 用户号为1-10 unsigned char aucLoginFlg[MAX_USR_NUM]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - (void)ArrayFunction { unsigned char ucUserNo; for (ucUserNo = 1; ucUserNo < 11; ucUserNo++) // 10已经越界了 { aucLoginFlg[User_No] = ucUserNo; … … } }
指针释放后,该指针可能还是指向原有的内存块,可能不是,变成一个野指针,一般用户不会对它再操作,但用户失误情况下对它的操作可能导致程序崩溃。 正例: - (void)memmoryFunction { unsigned char *pucBuffer = NULL; pucBuffer = GetBuffer(sizeof(DWORD)); if (NULL != pucBuffer) // 申请的内存指针必须进行有效性验证 { // 申请的内存使用前必须进行初始化 memset(pucBuffer, 0xFF, sizeof(DWORD)); } …. FreeBuffer(pucBuffer); // 申请的内存使用完毕必须释放 pucBuffer = NULL; // 申请的内存释放后指针置为空 … }
9.2.指针使用
9.3.类
正例: - (void)viewDidLoad { [super viewDidLoad]; }
@interfaceClassName(Private) - (void)test; @end - (void)test { } 10. 断言与错误处理断言是对某种假设条件进行检查(可理解为若条件成立则无动作,否则应报告)。它可以快速发现并定位软件问题,同时对系统错误进行自动报警。断言可以对在系统中隐藏很深,用其它手段极难发现的问题进行定位,从而缩短软件问题定位时间,提高系统的可测性。在实际应用时,可根据具体情况灵活地设计断言。
(1)#define ASSERT_EXIT_M 中断当前程序执行,打印中断发生的文件、行号,该宏一般在单调时使用。 (2)#define ASSERT_CONTINUE_M 打印程序发生错误或异常的文件,行号,继续进行后续的操作,该宏一般在联调时使用。 (3)#define ASSERT_OK_M 空操作,程序发生错误情况时,继续进行,可以通过适当的方式通知后台的监控或统计程序,该宏一般在RELEASE版本中使用。
正例: BYTE StoreCsrMsg(WORD wIndex, T_CMServReq *ptMsgCSR) { WORD wStoreIndex; T_FuncRet tFuncRet; Assert (wIndex < MAX_DATA_AREA_NUM_A); // 使用断言检查索引 Assert (ptMsgCSR != NULL); // 使用断言检查指针 … // 其它代码 return OK_M; } 11. 其它补充
ViewBounds.size.height = VIEW_BOUNDS_HEIGHT; 反例: ViewBounds.size.height = 150; Height = 150;
typedef enum { WIN_SIZE_NORMAL = 0, WIN_SIZE_SMALL }WinSize; 反例: typedef enum { WIN_SIZE_NORMAL, WIN_SIZE_SMALL }WinSize;
|
相关文章推荐
- iOS中读取照片库
- “第一次亲密接触”——iOS中策略模式初运用
- iOS应用目录
- iPhone自动旋转控制代码-IOS开发
- IOS常见问题之:clang: error: no such file or directory
- 实现一段字符串中部分内容字体颜色大小变化
- 值得深思:美国感恩节78.3%的网购来自iOS
- iOS后台运行
- iOS NSURLConnection GET和POST
- iOS笔记19
- IOS嵌入网页工具
- iOS笔记18
- iOS开发★★资源汇总参考
- 解决Xcode 7打包的应用与iOS 9的兼容问题
- iOS笔记17
- iOS笔记16
- iOS开发系列--让你的应用“动”起来【转载】
- iOS笔记13
- ReactNativeiOS(二)读书记录 7JSX在React-Native中的应用
- iOS笔记12