iOS Coding Guidelines(代碼指南)
| 版本號(hào) | 編寫人 | 日期 |
|---|---|---|
| 2.0 | 搶手的哥 | 2019-06-05 |
一、命名基礎(chǔ)
駝峰命名
- 針對(duì)屬性、變量、方法等均采用小寫字母開頭的駝峰命名準(zhǔn)則。
- 針對(duì)類、枚舉、宏等均采用大寫字母開頭的駝峰命名準(zhǔn)則。
清晰性
最好是既清晰又簡(jiǎn)短,但不要為簡(jiǎn)短而喪失清晰性
示例:
removeObject:反例:
remove名稱通常不縮寫,即使名稱很長(zhǎng),也要拼寫完全
示例:
destinationSelection反例:
destSel
我們盡可能遵守 Apple 的命名約定,其推薦使用長(zhǎng)的,描述性強(qiáng)的方法和變量名,使其閱讀起來(lái)更加清晰易懂。不能隨意使用縮寫,導(dǎo)致他人閱讀代碼困難。
一致性
- 盡可能使用與 Cocoa 編程接口命名保持一致的名稱。如果你不太確定某個(gè)命名的一致性,請(qǐng)瀏覽一下頭文件。
- 在使用多態(tài)方法的類中,命名的一致性非常重要。在不同類中實(shí)現(xiàn)相同功能的方法應(yīng)該具有相同的名稱
- 示例:
- (NSInteger)tag - 示例:
- (void)setStringValue:(NSString *)
前綴
前綴是名稱的重要組成部分,它們可以區(qū)分應(yīng)用的功能范疇。前綴可以防止與第三方開發(fā)者之間的命名沖突
- 前綴有規(guī)定的格式。它由兩到三個(gè)大寫字符組成,不能使用下劃線與子前綴
- 命名 class, protocol, struct, 函數(shù),常量時(shí)使用前綴;
- 命名成員方法時(shí)不使用前綴,因?yàn)榉椒ㄒ呀?jīng)在它所在類的命名空間中;
- 同理,命名結(jié)構(gòu)體字段時(shí)也不使用前綴
二、方法命名【強(qiáng)制】
一般性規(guī)則
為方法命名時(shí),請(qǐng)考慮如下一些一般性規(guī)則:
- 小寫第一個(gè)單詞的首字符,大寫隨后單詞的首字符,不使用前綴。有兩種例外情況:
- 方法名以廣為人知的大寫字母縮略詞(如 TIFF or PDF)開頭
- 私有方法可以使用統(tǒng)一的前綴來(lái)分組和辨識(shí)
表示對(duì)象行為的方法,名稱以動(dòng)詞開頭
示例:
- (void)invokeWithTarget:(id)target:示例:
- (void)selectTabViewItem:(NSTableViewItem *)tableViewItem如果方法返回方法接收者的某個(gè)屬性,直接用屬性名稱命名。不要使用 get,除非是間接返回一個(gè)或多個(gè)值。
示例:
- (NSSize)cellSize反例:
- (NSSize)getCellSize不要使用 and 來(lái)連接用屬性作參數(shù)關(guān)鍵字
示例:
- (NSInteger)runModalForDirectory:(NSString *)path file:(NSString *)name反例:
- (NSInteger)runModalForDirectory:(NSString *)path andFile:(NSString *)name
方法參數(shù)
命名方法參數(shù)時(shí)要考慮如下規(guī)則:
如同方法名,參數(shù)名小寫第一個(gè)單詞的首字符,大寫后繼單詞的首字符。
示例:
removeObject:(id)anObject不要在參數(shù)名中使用 pointer 或 ptr,讓參數(shù)的類型來(lái)說明它是指針
避免使用 one, two,…,作為參數(shù)名
避免為節(jié)省幾個(gè)字符而縮寫
三、實(shí)例變量與數(shù)據(jù)類型命名【強(qiáng)制】
描述性的單詞(有意義)+ 變量類型
私有變量:
私有變量放在 .m 文件中聲明 以 _ 開頭,第一個(gè)單詞首字母小寫
例子:NSString * _somePrivateVariable
屬性變量:
正例:@property (nonatomic, strong) UILabel *nameLabel;
注意nonatomic和strong之間有一個(gè)空格,*號(hào)之前有空格,之后沒有
反例:@property(strong,nonatomic)UILabel * lab;
如果實(shí)例變量別設(shè)計(jì)為可被訪問的,確保編寫了訪問方法并注意讀寫權(quán)限。
枚舉常量
- 使用枚舉來(lái)定義一組相關(guān)的整數(shù)常量
typedef NS_ENUM(NSInteger, NSMatrixMode) {
NSRadioModeMatrix = 0,
NSHighlightModeMatrix = 1,
NSListModeMatrix = 2,
NSTrackModeMatrix = 3
};
其他常量
- 通常不使用 #define 來(lái)創(chuàng)建常量。如上面所述,整數(shù)常量請(qǐng)使用枚舉。
- 使用大寫字母來(lái)定義預(yù)處理編譯宏。如:
#ifdef DEBUG - 為 notification 名定義大駝峰字符串常量,從而能夠利用編譯器的拼寫檢查,減少書寫錯(cuò)誤。
四、圖片資源命名
模塊名+功能名+控件名+狀態(tài)
photoBrowser_btn_selected photoBrowser_btn_unselected
五、可接受的縮略語(yǔ)
在設(shè)計(jì)編程接口時(shí),通常名稱不要縮寫。下面列出的縮寫要么是固定下來(lái)的要么是過去被廣泛使用的,所以可以繼續(xù)使用。關(guān)于縮寫有一些額外的注意事項(xiàng):
- 標(biāo)準(zhǔn) C 庫(kù)中長(zhǎng)期使用的縮寫形式是可以接受的。如:”alloc”, “getc”
- 你可以在參數(shù)名中更自由地使用縮寫。如: imageRep, col(column), obj, otherWin
常見的縮寫
| 縮寫 | 含義 | 縮寫 | 含義 |
|---|---|---|---|
| alloc | Allocate | alt | Alternate |
| app | Application | calc | Calculate |
| dealloc | dealloc | func | Function |
| horiz | Horizontal | info | Information |
| init | Initialize | int | Integer |
| max | Maximum | min | Minimum |
| msg | Message | nib | Interface Builder archive |
| pboard | Pasteboard | rect | Rectangle |
| Rep | Representation | temp | Temporary |
| vert | Vertical |
補(bǔ)充的縮寫
| 縮寫 | 含義 | 縮寫 | 含義 |
|---|---|---|---|
| idx | Index | btn | Button |
| proj | Project | pro | Professional |
| pwd | Password | pic | Picture |
| str | String | img | Image |
| VC | ViewController |
五、編碼格式
星號(hào)(*)位置
定義一個(gè)對(duì)象時(shí),*靠近變量
示例:
NSString *userName;
統(tǒng)一的ViewController模板(代碼縮進(jìn)、Method進(jìn)行分組、大括號(hào)寫法)
- import引用分組劃分
- 使用property與局部變量,不使用用全局變量(不能顯性區(qū)分作用域)
- 空格與換行建議(參照iOS SDK API)
- 方法功能區(qū)域性劃分
#import "GMBaseViewController.h"
/**
HomePage
*/
@interface HomePageViewController : GMBaseViewController
/** 項(xiàng)目Id */
@property (nonatomic, copy) NSString *projectId;
@end
#import "HomePageViewController.h"
#import "HomePageTableViewCell" //View
#import "HomePageListRequest" //Model數(shù)據(jù)類
#import "ProjectViewController" //非本頁(yè)面所用
@interface GMHPViewController ()
@end
@implementation GMHPViewController
#pragma mark - LifeCycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setupView];
[self loadData];
}
#pragma mark - Custom Methods
- (void)setupView {
}
#pragma mark - Event Response
#pragma mark - Data && Net
- (void)loadData {
}
#pragma mark - UITableViewDataSource && UITableViewDelegate
#pragma mark - CustomDelegate
#pragma mark - Getter && Setter
條件語(yǔ)句
- 條件判斷語(yǔ)句執(zhí)行主體不管是 if 里面還是 else 里面都必須要使用大括號(hào)包住, 即使代碼是一行的情況(Apple SSL/TLS gotofail)。for 循環(huán)同樣。
- if-else中,else不另起一行,與if的反括號(hào)在同一行,如下段代碼所示,注意else前后均有空格。
- switch-case中,建議所有case和default后的代碼塊均用{}包裹。
if(success){
...
} else {
...
}
for(int i = 0 ; i < 10 ; i++){
...
}
單一原則
- 每個(gè)函數(shù)的職責(zé)都應(yīng)該劃分明確(如類一樣)
模型解析(MJExtension)
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
return @{@"Id" : @"id"};
}
+ (NSDictionary *)mj_objectClassInArray {
return @{@“block” : @"GMBlockModel"};
}
其他
- 子類重寫父類方法一般需先調(diào)用父類方法
- (void)viewDidLoad {
[super viewDidLoad];
...
}
- 單模塊多頁(yè)面可新建模塊Header類,統(tǒng)一導(dǎo)入共用類,設(shè)定常量等。非全局不可定義在
PCH中
六、代碼注釋
優(yōu)秀的代碼大部分是可以自描述的,我們完全可以用代碼本身來(lái)表達(dá)它到底在干什么,而不需要注釋的輔助。
但并不是說一定不需要寫注釋,有以下三種情況需要編寫注釋:
- 公共接口(注釋要告訴閱讀代碼的人,當(dāng)前類能實(shí)現(xiàn)什么功能,譬如:基礎(chǔ)類、工具類)
- 涉及到比較深層專業(yè)知識(shí)及業(yè)務(wù)邏輯的代碼(注釋要體現(xiàn)出實(shí)現(xiàn)原理和思想)
- 容易產(chǎn)生歧義的代碼(但是嚴(yán)格來(lái)說,容易讓人產(chǎn)生歧義的代碼是不允許存在的)
import注釋
如果有一個(gè)以上的import語(yǔ)句,就對(duì)這些語(yǔ)句進(jìn)行分組,每個(gè)分組的注釋是可選的。
屬性注釋
/** 注釋 */
@property (nonatomic, strong) UIView *headerView;
枚舉注釋
typedef NS_ENUM(NSInteger, RefreshDateType) {
/** 新建 */
RefreshDateTypeTaskMain = 1,
/** 編輯 */
RefreshDateTypeEdit,
/** 重派 */
RefreshDateTypeAssign,
/** 新建子任務(wù) */
RefreshDateTypeSubTask,
/** 任務(wù)派發(fā)(進(jìn)度管理模塊) */
RefreshDateTypeTaskDis,
/** 任務(wù)變更(進(jìn)度管理模塊) */
RefreshDateTypeTaskChanged,
};
方法聲明注釋
公開接口,重要的方法,分類,以及協(xié)議都應(yīng)該伴隨注釋。方法的注釋使用Xcode自帶注釋快捷鍵:Commond+option+/或者///,這兩種注釋方式可被Xcode中Quick Help識(shí)別
/**
<#Description#>
@param tableView <#tableView description#>
@param section <#section description#>
@return <#return value description#>
*/
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
...
}
///<#Description#>
- (void)getUserInfo {
...
}
<font size=2 color=#4A7EC0>參考文檔:</font>Apple Coding Guidelines for Cocoa
七、其他事項(xiàng)
1.【推薦】條件過多、過長(zhǎng)時(shí)應(yīng)該換行
if ( condition1 &&
condition2 &&
condition3 ) {
}
2.【強(qiáng)制】二元運(yùn)算符與變量之間必須有空格
width = 5 + 5;
height = width * 2;
length = width + height;
for (int i = 0; i < 10; i++)
3.【強(qiáng)制】NSArray泛型
如果NSArray中存儲(chǔ)數(shù)據(jù)類型是統(tǒng)一的,必須如下使用
/** modelArray */
@property (nonatomic, strong) NSArray <GCBModel *> *modelArray;
4.【強(qiáng)制】block循環(huán)引用問題<特別關(guān)注>
__weak_self;
[selectPerVC setSingleResultBlock:^(ContactModel *resultModel) {
__strong_self;
}];
5【強(qiáng)制】枚舉使用
項(xiàng)目中兩個(gè)以上的區(qū)分邏輯要使用枚舉,使用枚舉值賦值的時(shí)候不能使用枚舉的值(1、2、3… 等)
正例:self.dataType = RefreshDateTypeTaskMain;
反例:self.dataType = 1;
6【強(qiáng)制】加載xib
xib名稱用NSStringFromClass(),避免書寫錯(cuò)誤
正例:[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([DXRecommendTagVCell class]) bundle:nil] forCellReuseIdentifier:ID];
反例:[self.tableView registerNib:[UINib nibWithNibName:@"DXRecommendTagVCell" bundle:nil] forCellReuseIdentifier:ID];
7【強(qiáng)制】三目運(yùn)算符
三目運(yùn)算符使用時(shí)注意?和:空格
正例:NSString *string = model.isSelected ? @"已選中" : @"未選中";
禁止連續(xù)使用三目運(yùn)算符
反例:return indexPath.row == 0 ? 109 : indexPath.row == 1 ? 138 : indexPath.row == 10 ? 45 : indexPath.row == 11 ? [PublicPhotoBrowserView getCollecHeiImageCount:self.taskModel.imgsArray.count remainCount:9 - self.taskModel.filesArray.count width: ScreenW - 30 detail:NO]+[PublicPhotoBrowserView publicPhotoGetFilesHeight:self.taskModel.filesArray.count singleHeight:0] : 55