iOS軟件代碼規範

 

 

 

 

 

 

 

 

 

 

 

 

 


   程序員

 

 

     4編程

1. 指導原則 5數組

2. 佈局 5安全

2.1. 文件佈局 6數據結構

2.2. 基本格式 8框架

2.3. 對齊 9編輯器

2.4. 空行空格 11函數

2.5. 斷行 13工具

3. 註釋 14佈局

4. 命名規則 17

4.1. 基本規則 17

4.2. 資源命名 19

5. 變量,常量,宏與類型 19

5.1. 變量、常量以及宏 19

5.2. 類型 21

6. 表達式與語句 22

7. 函數、方法、接口 27

8. 頭文件 28

9. 可靠性 29

9.1. 內存使用 29

9.2. 指針使用 31

9.3. 32

10. 斷言與錯誤處理 32

11. 其它補充 33

 

 

 
   

本規範針對於iOS的object-c開發語言。  

1. 指導原則

【原則1-1】首先是爲人編寫程序,其次纔是計算機。

說明:這是軟件開發的基本要點,軟件的生命週期貫穿產品的開發、測試、生產、用戶使用、版本升級和後期維護等長期過程,只有易讀、易維護的軟件代碼才具備生命力。

 

【原則1-2】保持代碼的簡明清晰,避免過度的編程技巧。

說明:簡單是最美。保持代碼的簡單化是軟件工程化的基本要求。不要過度追求技巧,不然會下降程序的可讀性。

 

【原則1-3】編程時首先達到正確性,其次考慮效率。

說明:編程首先考慮的是知足正確性、健壯性、可維護性、可移植性等質量因素,最後才考慮程序的效率和資源佔用。

 

【原則1-4】編寫代碼時要考慮到代碼的可測試性。

說明:不能夠測試的代碼是沒法保障質量的,開發人員要牢記這一點來設計、編碼。實現設計功能的同時,要提供能夠測試、驗證的方法。

 

【原則1-5】函數(方法)是爲一特定功能而編寫,不是萬能工具箱。

說明:方法是一個處理單元,是有特定功能的,因此應該很好地規劃方法,不能是全部東西都放在一個方法裏實現

 

【原則1-6】鼓勵多加註釋。

 

【原則1-7】內存空間在哪分配在哪釋放。

 

2. 佈局

程序佈局的目的是顯示出程序良好的邏輯結構,提升程序的準確性、連續性、可讀性、可維護性。更重要的是,統一的程序佈局和編程風格,有助於提升整個項目的開發質量,提升開發效率,下降開發成本。同時,對於普通程序員來講,養成良好的編程習慣有助於提升本身的編程水平,提升編程效率。所以,統一的、良好的程序佈局和編程風格不只僅是我的主觀美學上的或是形式上的問題,並且會涉及到產品質量,涉及到我的編程能力的提升,必須引發你們重視。

2.1. 文件佈局

【規則2-1-1】遵循統一的佈局順序來書寫頭文件。

 

說明:如下內容若是某些節不須要,能夠忽略。可是其它節要保持該次序。

頭文件佈局:

          文件頭(參見「註釋」一節)

  #import (依次爲標準庫頭文件、非標準庫頭文件)

          全局宏

常量定義

          全局數據類型

          類定義

 

正例:

/***************************************************************************

 *                                文件引用

 ***************************************************************************/

 

 

/***************************************************************************

 *                                 類引用

 ***************************************************************************/

 

 

/***************************************************************************

 *                                 宏定義

 ***************************************************************************/

 

 

/***************************************************************************

 *                                 常量

 ***************************************************************************/

 

 

/***************************************************************************

 *                                類型定義

 ***************************************************************************/

 

 

/ ***************************************************************************

 *                                 類定義

 ***************************************************************************/

 

 

【規則2-1-2】遵循統一的佈局順序來書寫實現文件。

說明:如下內容若是某些節不須要,能夠忽略。可是其它節要保持該次序。

實現文件佈局:

          文件頭(參見「註釋」一節)

          #import (依次爲標準庫頭文件、非標準庫頭文件) 

          文件內部使用的宏

常量定義

          文件內部使用的數據類型

全局變量

本地變量(即靜態全局變量)

      類的實現

 

正例:

/***************************************************************************

 *                                文件引用

 ***************************************************************************/

 

 

/***************************************************************************

 *                                 宏定義

 ***************************************************************************/

 

 

/***************************************************************************

 *                                 常量

 ***************************************************************************/

 

 

/***************************************************************************

 *                                類型定義

 ***************************************************************************/

 

 

/***************************************************************************

 *                                全局變量

 ***************************************************************************/

 

 

/***************************************************************************

 *                                 原型

 ***************************************************************************/

 

 

/ ***************************************************************************

 *                                類特性

 ***************************************************************************/

@implementation ClassName

 

@synthesize variableName;

 

 

/ ***************************************************************************

 *                                類的實現

 ***************************************************************************/

 

 

【規則2-1-4】包含標準庫頭文件用尖括號 < >,包含非標準庫頭文件用雙引號 「 」。

正例

#import <stdio.h>

#import 「heads.h

 

2.2. 基本格式

【規則2-2-1if、else、else if、for、while、do等語句自佔一行,執行語句不得緊跟其後。不論執行語句有多少都要加 { }。

說明:這樣能夠防止書寫失誤,也易於閱讀。

正例:

if (varible1 < varible2)

{

varible1 = varible2;

}

反例:下面的代碼執行語句緊跟if的條件以後,並且沒有加{},違反規則。

 

if (varible1 < varible2) varible1 = varible2;  

 

【規則2-2-2】定義指針類型的變量,*應放在變量前。

正例

float  *pfBuffer;

反例

float*  pfBuffer;

 

〖建議2-2-1〗源程序中關係較爲緊密的代碼應儘量相鄰。

說明:這樣便於程序閱讀和查找。

正例

iLength     = 10;

iWidth = 5;     // 矩形的長與寬關係較密切,放在一塊兒。

StrCaption = 「Test」;

反例

iLength = 10;

strCaption = 「Test」;

iWidth = 5;

 

2.3. 對齊

【規則2-3-1】 禁止使用TAB鍵,必須使用空格進行縮進。縮進爲4個空格。

說明:消除不一樣編輯器對TAB處理的差別,有的代碼編輯器能夠設置用空格代替TAB鍵。

 

【規則2-3-2】程序的分界符‘{’和‘}’應獨佔一行而且位於同一列,同時與引用它們的語句左對齊。{ }以內的代碼塊使用縮進規則對齊。

說明:這樣使代碼便於閱讀,而且方便註釋。

do while語句和結構的類型化時能夠例外,while條件和結構名可與 } 在同一行。

正例

(void)Function:(int)iVar

{                       // 獨佔一行並與引用語句左對齊。

while (condition)

{

doSomething();   // 與{ }縮進4

}

}

反例:

void Function(int iVar){

while (condition){

DoSomething();

}}

 

【規則2-3-3】結構型的數組、多維的數組若是在定義時初始化,按照數組的矩陣結構分行書寫。

正例

int aiNumbers[4][3] =

{

1, 1, 1,

2, 4, 8,

3, 9, 27,

4, 16, 64

}

 

【規則2-3-4】相關的賦值語句等號對齊。

正例

tPDBRes.wHead =  0;

tPDBRes.wTail =  wMaxNumOfPDB - 1;

tPDBRes.wFree =  wMaxNumOfPDB;

tPDBRes.wAddress =  wPDBAddr;

tPDBRes.wSize =  wPDBSize;

 

〖建議2-3-1〗在switch語句中,每個case分支和default要用{ }括起來,{ }中的內容須要縮進。

說明:使程序可讀性更好。

正例

      switch (iCode)

      {

          case 1:              

{

              DoSomething();   // 縮進4

break;

}

          case 2:

          { // 每個case分支和default要用{}括起來

              DoOtherThing();

              break;

          }

          …                    // 其它case分支

          default:

  {

              DoNothing();

              break;

  }

      }

 

2.4. 空行空格

【規則2-4-1】函數(方法)塊之間使用兩個空行分隔。

說明:空行起着分隔程序段落的做用。適當的空行可使程序的佈局更加清晰。

正例

(void)hey

{

[hey實現代碼]

}

// 空一行

// 空一行

(void)ack

{

[ack實現代碼]

}

反例

void Foo::Hey(void)

{

  [Hey實現代碼]

}

void Foo::Ack(void)

{

[Ack實現代碼]

}

// 兩個函數的實現是兩個邏輯程序塊,應該用空行加以分隔。

 

【規則2-4-2】一元操做符如「!」、「~」、「++」、「--」、「*」、「&」(地址運算符)等先後不加空格。「[]」、「.」、「->」這類操做符先後不加空格。

正例

!bValue

~iValue

++iCount

*strSource

&fSum

aiNumber[i] = 5;

tBox.dWidth

tBox->dWidth

 

【規則2-4-3】多元運算符和它們的操做數之間至少須要一個空格。

正例

fValue  =  fOldValue;

fTotal  +  fValue

iNumber +=  2;

 

【規則2-4-4】關鍵字以後要留空格。

說明:if、for、while等關鍵字以後應留一個空格再跟左括號‘(’,以突出關鍵字。

 

【規則2-4-5】函數名以後不要留空格。

說明:函數名後緊跟左括號‘(’,以與關鍵字區別。

 

【規則2-4-6】方法名與形參不能留空格,返回類型與方法標識符有一個空格。

說明:方法名後緊跟’:’,而後緊跟形參, 返回類型’(‘與’-‘之間有一個空格。

正例:

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations.
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

 

【規則2-4-7】‘(’向後緊跟,‘)’、‘,’、‘;’向前緊跟,緊跟處不留空格。‘,’以後要留空格。‘;’不是行結束符號時其後要留空格。

正例:

例子中的  表明空格。

for(i=0;i<MAX_BSC_NUM;i++)

{

DoSomething(iWidth,iHeight);

}

 

【規則2-4-8】註釋符與註釋內容之間要用一個空格進行分隔。

正例:

/* 註釋內容 */

// 註釋內容

反例: 

/*註釋內容*/

//註釋內容

 

2.5. 斷行

【規則2-5-1】長表達式(超過80列)要在低優先級操做符處拆分紅新行,操做符放在新行之首(以便突出操做符)。拆分出的新行要進行適當的縮進,使排版整齊。

說明:條件表達式的續行在第一個條件處對齊。

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]);

 

【規則2-5-2】函數(方法)聲明時,類型與名稱不容許分行書寫。

正例

extern double FAR CalcArea(double dWidth, double dHeight);

反例

extern double FAR

CalcArea(double dWidth, double dHeight);

3. 註釋

註釋有助於理解代碼,有效的註釋是指在代碼的功能、意圖層次上進行註釋,提供有用、額外的信息,而不是代碼表面意義的簡單重複。

 

【規則3-1C語言的註釋符爲「/* … */」。C++語言中,多行註釋採用「/* … */」,單行註釋採用「// …」。

 

〖建議3-1〗無論多行仍是單行,採用註釋符「/* … */」。

 

【規則3-2】通常狀況下,源程序有效註釋量必須在30%以上。

說明:註釋的原則是有助於對程序的閱讀理解,註釋不宜太多也不能太少,註釋語言必須準確、易懂、簡潔。有效的註釋是指在代碼的功能、意圖層次上進行註釋,提供有用、額外的信息。

 

【規則3-3】註釋使用中文。

說明:對於特殊要求的可使用英文註釋,如工具不支持中文或國際化版本時。

 

【規則3-4】文件頭部必須進行註釋,包括:.h文件、.c文件、.m文件、.inc文件、.def文件、編譯說明文件.cfg等。

說明:註釋必須列出:版權信息、文件標識、內容摘要、版本號、做者、完成日期、修改信息等。修改記錄部分建議在代碼作了大修改以後添加修改記錄。備註:文件名稱,內容摘要,做者等部分必定要寫清楚。

正例:

下面是文件頭部的中文註釋:

/*********************************************************************

* 版權全部 (C)2011***有限公司

*

* 文件名稱: // 文件名

* 文件標識: // 見配置管理計劃書

* 內容摘要: // 簡要描述本文件的內容,包括主要模塊、函數及其功能的說明

* 其它說明: // 其它內容的說明

* 當前版本: // 輸入當前版本

* 做    者: // 輸入做者名字及單位

* 完成日期: // 輸入完成日期,例:20111129

 

* 修改記錄1// 修改歷史記錄,包括修改日期、修改者及修改內容

*    修改日期:

*    版 本 號://或版本號

*    修 改 人:

*    修改內容://修改緣由以及修改內容說明

* 修改記錄2:…

**********************************************************************/

 

【規則3-5】方法頭部應進行註釋,列出:函數的目的/功能、輸入參數、輸出參數、返回值、訪問和修改的表、修改信息等,除了函數(方法)名稱和功能描述必須描述外,其它部分建議寫描述。

說明:註釋必須列出:函數名稱、功能描述、輸入參數、輸出參數、返 值、修改信息等。備註:方法名稱、功能描述要正確描述。

正例:

/***********************************************************************

* 方法名稱: // 方法名稱

* 功能描述: // 方法功能、性能等的描述

* 輸入參數: // 輸入參數說明,包括每一個參數的做用、取值說明及參數間關係

* 輸出參數: // 對輸出參數的說明。

* 返 回 值: // 方法返回值的說明

* 其它說明: // 其它說明

***********************************************************************/

 

【規則3-6】註釋應與其描述的代碼相近,對代碼的註釋應放在其上方或右方(對單條語句的註釋)相鄰位置,不可放在下面,如放於上方則需與其上面的代碼用空行隔開。

說明:在使用縮寫時或以前,應對縮寫進行必要的說明。

正例: 

以下書寫比較結構清晰

 

/* 得到子系統索引 */

iSubSysIndex = aData[iIndex].iSysIndex;

 

/* 代碼段1註釋 */

[ 代碼段1 ]

 

/* 代碼段2註釋 */

[ 代碼段2 ]

反例1

以下例子註釋與描述的代碼相隔太遠。

/* 得到子系統索引 */

 

iSubSysIndex = aData[iIndex].iSysIndex;

反例2

以下例子註釋不該放在所描述的代碼下面。

 

iSubSysIndex = aData[iIndex].iSysIndex;

/* 得到子系統索引 */

反例3

以下例子,顯得代碼與註釋過於緊湊。

/* 代碼段1註釋 */

[ 代碼段1 ]

/* 代碼段2註釋 */

[ 代碼段2 ]

 

【規則3-7】全局變量要有詳細的註釋,包括對其功能、取值範圍、訪問信息及訪問時注意事項等的說明

正例

/*

* 變量做用說明

* 變量值說明

*/

BYTE g_ucTranErrorCode;

    

【規則3-8】註釋與所描述內容進行一樣的縮排。

說明:可以使程序排版整齊,並方便註釋的閱讀與理解。

正例: 

以下注釋結構比較清晰

- (int)doSomething

{

/* 代碼段1註釋 */

    [ 代碼段1 ]

 

    /* 代碼段2註釋 */

    [ 代碼段2 ]

 

反例

以下例子,排版不整齊,閱讀不方便;

int DoSomething(void)

{

/* 代碼段1註釋 */

    [ 代碼段1 ]

 

/* 代碼段2註釋 */

    [ 代碼段2 ]

}

 

〖建議3-2〗儘可能避免在註釋中使用縮寫,特別是不經常使用縮寫。

說明:在使用縮寫時,應對縮寫進行必要的說明。

 

4. 命名規則

4.1. 基本規則

好的命名規則能極大地增長可讀性和可維護性。同時,對於一個有上百我的共同完成的大項目來講,統一命名約定也是一項必不可少的內容。本章對程序中的全部標識符(包括變量名、常量名、函數名、類名、結構名、宏定義等)的命名作出約定。

【規則4-1】標識符要採用英文單詞或其組合,便於記憶和閱讀,切忌使用漢語拼音來命名。

說明:標識符應當直觀且能夠拼讀,可望文知義,避免令人產生誤解。程序中的英文單詞通常不要太複雜,用詞應當準確。

 

【規則4-2嚴格禁止使用連續的下劃線,下劃線也不能出如今標識符頭或結尾(預編譯開關除外)。

說明:這樣作的目的是爲了使程序易讀。由於 variable_name variable__name 很難區分,下劃線符號_’若出如今標識符頭或結尾,容易與不帶下劃線‘_’的標識符混淆。

 

【規則4-3】程序中不要出現僅靠大小寫區分的類似的標識符。

 

【規則4-4宏、常量名都要使用大寫字母, 用下劃線 ‘_’ 分割單詞。預編譯開關的定義使用下劃線 ‘_’ 開始。

正例 DISP_BUF_SIZEMIN_VALUEMAX_VALUE 等等。

 

【規則4-5】程序中局部變量不要與全局變量重名。

說明:儘管局部變量和全局變量的做用域不一樣而不會發生語法錯誤,但容易令人誤解。

 

【規則4-6】使用一致的前綴來區分變量的做用域。

說明:變量活動範圍前綴規範以下(少用全局變量):

   g_      :  全局變量

   s_        模塊內靜態變量

           局部變量不加範圍前綴

 

【規則4-7】方法名用小寫字母開頭的單詞組合而成

說明:方法名力求清晰、明瞭,經過方法名就可以判斷方法的主要功能。方法名中不一樣意義字段之間不要用下劃線鏈接,而要把每一個字段的首字母大寫以示區分。方法命名採用大小寫字母結合的形式,但專有名詞不受限制。

 

【規則4-8】類中的屬性以小寫字母m_開頭。

說明:參考匈牙利命名規則,常見的簡寫以下:

整型 n

指針 p

字符串 str

布爾 b

字符 c

函數 fn

 

正例 

@interface CMainMenu

{

    int m_nWidth;

    NString *m_strName;

    BOOL m_bCheck;

}

 

〖建議4-1〗儘可能避免名字中出現數字編號,如Value一、Value2等,除非邏輯上的確須要編號。

 

〖建議4-2〗標識符前最好不加項目、產品、部門的標識

說明:這樣作的目的是爲了代碼的可重用性。

 

4.2. 資源命名

● 字符串:以「IDS_」開頭,如:IDS_VIEW

● 圖片:以「IDB_」開頭,如:IDB_COREICON

 

5. 變量,常量,宏與類型

變量、常量和數據類型是程序編寫的基礎,它們的正確使用直接關係到程序設計的成敗,變量包括全局變量、局部變量和靜態變量,常量包括數據常量和指針常量,類型包括系統的數據類型和自定義數據類型。本章主要說明變量、常量與類型使用時必須遵循的規則和一些需注意的建議,關於它們的命名,參見命名規則。  

5.1. 變量、常量以及宏

【規則5-1-1】一個變量有且只有一個功能,儘可能不要把一個變量用做多種用途。

說明:一個變量只用來表示一個特定功能,不能把一個變量做多種用途,即同一變量取值不一樣時,其表明的意義也不一樣。

 

【規則5-1-2】循環語句與判斷語句中,不容許對其它變量進行計算與賦值。

說明:循環語句只完成循環控制功能,if語句只完成邏輯判斷功能,不能完成計算賦值功能。

正例

do

{

             [處理語句]

      cInput = GetChar();

         } while (cInput == 0);

 反例:

         do

{

             [處理語句]

         } while (cInput = GetChar());

   

【規則5-1-3】宏定義中若是包含表達式或變量,表達式和變量必須用小括號括起來。

說明:在宏定義中,對錶達式和變量使用括號,能夠避免可能發生的計算錯誤。

正例:

#define  HANDLE(A, B)   (( A ) / ( B ))

反例:

#define  HANDLE(A, B)   (A / B)

 

【規則5-1-4】宏名大寫字母。

正例:

#define  BUTTON_WIDTH    (int)320

反例:

#define  kButtonWidth    (int)320

 

【規則5-1-5】宏常量要指定類型。

說明:不一樣的編譯器,默認類型不同。

正例:

#define  BUTTON_WIDTH    (int)320

反例:

#define  BUTTON_WIDTH    320

 

 

〖建議5-1-1〗對於全局變量經過統一的函數訪問。

說明:能夠避免訪問全局變量時引發的錯誤。

正例:

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-1-4〗最好不要在語句塊內聲明局部變量。

5.2. 類型

〖建議5-2-1〗結構是針對一種事務的抽象,功能要單一,不要設計面面俱到的數據結構。

說明:設計結構時應力爭使結構表明一種現實事務的抽象,而不是同時表明多種。結構中的各元素應表明同一事務的不一樣側面,而不該把描述沒有關係或關係很弱的不一樣事務的元素放到同一結構中。

正例

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;

 

〖建議5-2-2〗內存對齊。

說明:合理排列結構中元素順序,可節省空間並增長可理解性。

正例:以下形式,不只可節省字節空間,可讀性也變好了。

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等基本語句的一些規則與建議。

 

【規則6-1】一條語句只完成一個功能。

說明:複雜的語句閱讀起來,難於理解,並容易隱含錯誤。變量定義時,一行只定義一個變量。

正例

int  iHelp;    

int  iBase;

int  iResult;

 

iHelp   = iBase;

iResult = iHelp + GetValue(&iBase);

反例:

int iBase, iResult;                 // 一行定義多個變量

 

iResult = iBase + GetValue(&iBase); // 一條語句實現多個功能,iBase有兩種用途。

 

【規則6-2】在表達式中使用括號,使表達式的運算順序更清晰。

說明:因爲將運算符的優先級與結合律熟記是比較困難的,爲了防止產生歧義並提升可讀性,即便不加括號時運算順序不會改變,也應當用括號肯定表達式的操做順序。

正例

 

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

 

反例:

 

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

 

【規則6-3】避免表達式中的附加功能,不要編寫太複雜的複合表達式。

說明:帶附加功能的表達式難於閱讀和維護,它們經常致使錯誤。對於一個好的編譯器,下面兩種狀況效果是同樣的。

正例

aiVar[1] = aiVar[2] + aiVar[3];

aiVar[4]++;

iResult = aiVar[1] + aiVar[4];

aiVar[3]++;

 

反例   

iResult = (aiVar[1] = aiVar[2] + aiVar[3]++) + ++aiVar[4] ;

 

【規則6-4】不可將布爾變量和邏輯表達式直接與YESNO或者一、0進行比較。

說明:TUREFALSE的定義值是和語言環境相關的,且可能會被重定義的。

正例:

設bFlag 是布爾類型的變量

if (bFlag)    // 表示flag爲真

if (!bFlag)   // 表示flag爲假

反例:

設bFlag 是布爾類型的變量

 

if (bFlag == TRUE)

if (bFlag == 1)

if (bFlag == FALSE)  

if (bFlag == 0)

 

【規則6-5】在條件判斷語句中,當整型變量與0 比較時,不可模仿布爾變量的風格,應當將整型變量用「==」或「!=」直接與0比較。

正例

if (iValue == 0)  

 

if (iValue != 0)

 

反例

if (iValue) // 會讓人誤解 iValue是布爾變量

 

if (!iValue) 

 

【規則6-6】不可將浮點變量用「==」或「!=」與任何數字比較。

說明:不管是float仍是double類型的變量,都有精度限制。因此必定要避免將浮點變量用「==」或「!=」與數字比較,應該轉化成「>=」或「<=」形式。

正例

if ((fResult >= -EPSINON) && (fResult <= EPSINON))

反例:

if (fResult == 0.0) // 隱含錯誤的比較

 其中EPSINON是容許的偏差(即精度)。

 

【規則6-7】應當將指針變量用「==」或「!=」與nil比較。

說明:指針變量的零值是「空」(記爲NULL),即便NULL的值與0相同,可是二者意義不一樣。

正例:

if (pHead == nil)   // pHead與NULL顯式比較,強調pHead是指針變量

if (pHead != nil)

反例:

if (pHead == 0)       // 容易讓人誤解pHead是整型變量

if (pHead != 0)    

或者

if (pHead)       // 容易讓人誤解pHead是布爾變量

if (!pHead)

      

【規則6-8】在switch語句中,每個case分支必須使用break結尾,最後一個分支必須是default分支。

說明:避免漏掉break語句形成程序錯誤。同時保持程序簡潔。

對於多個分支相同處理的狀況能夠共用一個break,可是要用註釋加以說明。

正例

          switch (iMessage)

          {

case SPAN_ON:

{

                    [處理語句]

                    break;

               }

              case SPAN_OFF:

              {

                    [處理語句]

                    break;

              }

              default:

              {

                     [處理語句]

break;

              }    

          }

 

【規則6-9】不可在for 循環體內修改循環變量,防止for 循環失去控制。

 

〖建議6-1〗循環嵌套次數不大於3次。

 

〖建議6-2do while語句和while語句僅使用一個條件。

說明:保持程序簡潔。若是須要判斷的條件較多,建議用臨時布爾變量先計算是否知足條件。

正例

     BOOL bCondition;

 

     do

     {

         ……..

bCondition = ((tAp[iPortNo].bStateAcpActivity != PASSIVE)

               || (tAp[iPortNo].bStateLacpActivity != PASSIVE)) 

           && (abLacpEnabled[iPortNo])

           && (abPortEenabled[iPortNo])

 

      } while (bCondition);

 

 

〖建議6-3〗若是循環體內存在邏輯判斷,而且循環次數很大,宜將邏輯判斷移到循環體的外面。

說明:下面兩個示例中,反例比正例多執行了NUM -1次邏輯判斷。而且因爲前者總要進行邏輯判斷,使得編譯器不能對循環進行優化處理,下降了效率。若是NUM很是大,最好採用正例的寫法,能夠提升效率。

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();

    }

}

 

〖建議6-4for語句的循環控制變量的取值採用「半開半閉區間」寫法。

說明:這樣作更能適應c語言數組的特色,c語言的下標屬於一個「半開半閉區間」。

正例:

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. 函數、方法、接口

 

〖規則7-1方法不能爲多個目的服務。

正例

- (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;

 

〖規則7-2在組件接口中應該儘可能少使用外部定義的類型(重用,減小耦合)。

 

〖建議7-1避免函數有太多的參數,參數個數儘可能控制在5個之內。

說明:若是參數太多,在使用時容易將參數類型或順序搞錯,並且調用的時候也不方便。若是參數的確比較多,並且輸入的參數相互之間的關係比較緊密,不妨把這些參數定義成一個結構,而後把結構的指針當成參數輸入。

 

規則7-3對於有返回值的函數(方法),每個分支都必須有返回值。

說明:爲了保證對被調用函數返回值的判斷,有返回值的函數中的每個退出點都須要有返回值。

 

規則7-4對輸入參數的正確性和有效性進行檢查。

說明:不少程序錯誤是由非法參數引發的,咱們應該充分理解並正確處理來防止此類錯誤。

 

7-5防止將函數(方法)的參數做爲工做變量

說明:將函數的參數做爲工做變量,有可能錯誤地改變參數內容,因此很危險。對必須改變的參數,最好先用局部變量代之,最後再將該局部變量的內容賦給該參數。

 

〖建議7-6〗函數(方法)的功能要單一,不要設計多用途的函數(方法)

說明:多用途的函數每每經過在輸入參數中有一個控制參數,根據不一樣的控制參數產生不一樣的功能。這種方式增長了函數之間的控制耦合性,並且在函數調用的時候,調用相同的一個函數卻產生不一樣的效果,下降了代碼的可讀性,也不利於代碼調試和維護。

 

〖建議7-2函數(方法)體的規模不能太大,儘可能控制在200行代碼以內。

說明:冗長的函數不利於調試,可讀性差。

 

規則7-7避免設計多參數函數(方法)

 

8. 頭文件

規則8-1若是不是確實須要,應該儘可能避免頭文件包含其它的頭文件。

說明:頭文件中應避免包含其它不相關的頭文件,一次頭文件包含就至關於一次代碼拷貝。

 

規則8-2申明成員類,應該引用該類申明,而不是包含該類的頭文件。

說明:正例:

@class SubClassName;

@interface ClassName : NSObject

{

    SubClassName *m_pSubClassName;

}

反例:

#import 「SubClassName.h」;

@interface ClassName : NSObject

{

    SubClassName *m_pSubClassName;

}

 

9. 可靠性

爲保證代碼的可靠性,編程時請遵循以下基本原則,優先級遞減:

● 正確性,指程序要實現設計要求的功能。

● 穩定性、安全性,指程序穩定、可靠、安全。

● 可測試性,指程序要方便測試。

● 規範/可讀性,指程序書寫風格、命名規則等要符合規範。

● 全局效率,指軟件系統的總體效率。

● 局部效率,指某個模塊/子模塊/函數的自己效率。

● 我的表達方式/我的方便性,指我的編程習慣。

9.1. 內存使用

【規則9-1-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;

… …

}

}

 

【規則9-1-2】必須對動態申請的內存作有效性檢查,並進行初始化;動態內存的釋放必須和分配成對以防止內存泄漏,釋放後內存指針置爲nil

說明:對嵌入式系統,一般內存是有限的,內存的申請可能會失敗,若是不檢查就對該指針進行操做,可能出現異常,並且這種異常不是每次都出現,比較難定位。

指針釋放後,該指針可能仍是指向原有的內存塊,可能不是,變成一個野指針,通常用戶不會對它再操做,但用戶失誤狀況下對它的操做可能致使程序崩潰。

正例:

- (void)memmoryFunction

{

unsigned char *pucBuffer = NULL;

pucBuffer = GetBuffer(sizeof(DWORD));

if (NULL != pucBuffer) // 申請的內存指針必須進行有效性驗證

{

        // 申請的內存使用前必須進行初始化

memset(pucBuffer, 0xFF, sizeof(DWORD));

}

….

FreeBuffer(pucBuffer); // 申請的內存使用完畢必須釋放

pucBuffer = NULL; // 申請的內存釋放後指針置爲空

}

 

【規則9-1-3】變量在使用前應初始化,防止未經初始化的變量被引用。

說明:不一樣的編譯系統,定義的變量在初始化前其值是不肯定的。有些系統會初始化爲0,而有些不是。

9.2. 指針使用

【規則9-2-1】指針類型變量必須初始化爲nil

 

【規則9-2-2】指針不要進行復雜的邏輯或算術操做。

說明:指針加一的偏移,一般由指針的類型肯定,若是經過複雜的邏輯或算術操做,則指針的位置就很難肯定。

 

【規則9-2-3】減小指針和數據類型的強制類型轉化。

 

【規則9-2-4】對變量進行賦值時,必須對其值進行合法性檢查,防止越界等現象發生。

說明:尤爲對全局變量賦值時,應進行合法性檢查,以提升代碼的可靠性、穩定性。

 

【規則9-2-5】在哪申請在哪釋放。

 

【規則9-2-6】 非初始化方法中的alloc操做以前必需要nil判斷;。

 

【建議9-2-1】全局指針釋放後置爲nil值。

 

 

9.3. 

【規則9-3-1】在編寫派生類的賦值時,注意不要忘記對基類的成員變量從新賦值。

說明:除非在派生類中調用基類的賦值函數,不然基類變量不會自動被賦值。

正例:

- (void)viewDidLoad

{

    [super viewDidLoad];

}

 

【規則9-3-2】私有方法應該在實現文件中申明。

正例:

@interface ClassName(Private)

 

- (void)test;

 

@end

 

- (void)test

{

}

 

 

10. 斷言與錯誤處理

斷言是對某種假設條件進行檢查(可理解爲若條件成立則無動做,不然應報告)。它能夠快速發現並定位軟件問題,同時對系統錯誤進行自動報警。斷言能夠對在系統中隱藏很深,用其它手段極難發現的問題進行定位,從而縮短軟件問題定位時間,提升系統的可測性。在實際應用時,可根據具體狀況靈活地設計斷言。

 

【規則10-1】整個軟件系統應該採用統一的斷言。若是系統不提供斷言,則應該本身構造一個統一的斷言供編程時使用。

說明:整個軟件系統提供一個統一的斷言函數,如Assert(exp) 同時可提供不一樣的宏進行定義(可根據具體狀況靈活設計),如:

1#define ASSERT_EXIT_M 中斷當前程序執行,打印中斷髮生的文件、行號,該宏通常在單調時使用。

2#define ASSERT_CONTINUE_M 打印程序發生錯誤或異常的文件,行號,繼續進行後續的操做,該宏通常在聯調時使用。

3#define ASSERT_OK_M 空操做,程序發生錯誤狀況時,繼續進行,能夠經過適當的方式通知後臺的監控或統計程序,該宏通常在RELEASE版本中使用。

 

【規則10-2】正式軟件產品中應把斷言及其它調測代碼去掉(即把有關的調測開關關掉)。

說明:加快軟件運行速度。

 

〖建議10-1〗使用斷言檢查函數輸入參數的有效性、合法性。

說明:檢查函數的輸入參數是否合法,如輸入參數爲指針,則可用斷言檢查該指針是否爲空,如輸入參數爲索引,則檢查索引是否在值域範圍內。

正例:

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. 其它補充

【規則11-1】避免過多直接使用當即數。

正例

ViewBounds.size.height = VIEW_BOUNDS_HEIGHT;

反例:

ViewBounds.size.height = 150;

Height = 150;

 

【規則11-2】枚舉第一個成員要賦初始值。

正例

typedef enum

{

    WIN_SIZE_NORMAL = 0,

    WIN_SIZE_SMALL

}WinSize;

反例:

typedef enum

{

    WIN_SIZE_NORMAL,

    WIN_SIZE_SMALL

}WinSize;

 

【規則11-3addObject以前要非空判斷。

 

【規則11-4release版本代碼去掉NSLog打印,除了保留異常分支的NSLog

 

【規則11-5】禁止在代碼中直接寫死字符串資源,必需要用字符串ID替代。

說明:應該要考慮多語言國際化,儘可能使用NSLocalizedStringFromTable實現對字符串ID的引用

 

【規則11-6】對於框架設計,邏輯層應儘可能與UI層分離,下降耦合度。

 

【規則11-7】同等難度下,優先考慮代碼實現窗體建立。

說明:代碼實現窗體建立容易移植,優先考慮代碼實現來替代xib實現

相關文章
相關標籤/搜索