最近重構項目組件,看到項目中存在一些命名和方法分塊方面存在一些問題,結合平時經驗和 Apple官方代碼規範 在此整理出 iOS 工程規範。提出第一個版本,若是後期以爲有不完善的地方,繼續提出來不斷完善,文檔在此記錄的目的就是爲了你們的代碼可讀性較好,後來的人或者團隊裏面的其餘人看到代碼能夠不會由於代碼風格和可讀性上面形成較大時間的開銷。html
軟件的生命週期貫穿產品的開發,測試,生產,用戶使用,版本升級和後期維護等過程,只有易讀,易維護的軟件代碼才具備生命力。
- (void)getGooodsList { // ... } - (void)doHomework { if (self.hungry) { return; } if (self.thirsty) { return; } if (self.tired) { return; } papapa.then.over; }
//good if (condition1() && condition2() && condition3() && condition4()) { // Do something } //bad if (condition1() && condition2() && condition3() && condition4()) { // Do something }
return
來結束異常的狀況。- (void)doHomework { if (self.hungry) { return; } if (self.thirsty) { return; } if (self.tired) { return; } papapa.then.over; }
// bad if (self.hungry) self.eat() // good if (self.hungry) { self.eat() }
switch (menuType) { case menuTypeLeft: { // ... break; } case menuTypeRight: { // ... break; } case menuTypeTop: { // ... break; } case menuTypeBottom: { // ... break; } }
ViewController
結尾。例子:ApplyRecordsViewControllerView
結尾。例子:分界線:boundaryViews
結尾。好比商品分類數據源。categoriesCell
結尾。好比 MyProfileCellDelegate
或者 Datasource
結尾。好比 XQScanViewDelegate有時候咱們須要爲咱們建立的類設置一些註釋。咱們能夠在類的下面添加。git
枚舉的命名和類的命名相近。github
typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) { UIControlContentVerticalAlignmentCenter = 0, UIControlContentVerticalAlignmentTop = 1, UIControlContentVerticalAlignmentBottom = 2, UIControlContentVerticalAlignmentFill = 3, };
_
鏈接。K
開頭。後面遵循大寫駝峯命名。「不帶參數」#define HOME_PAGE_DID_SCROLL @"com.xq.home.page.tableview.did.scroll" #define KHomePageDidScroll @"com.xq.home.page.tableview.did.scroll"
書寫規則,基本上就是 @property 以後空一格,括號,裏面的 線程修飾詞、內存修飾詞、讀寫修飾詞,空一格 類 對象名稱
根據不一樣的場景選擇合適的修飾符。objective-c
@property (nonatomic, strong) UITableView *tableView; @property (nonatomic, assign, readonly) BOOL loading; @property (nonatomic, weak) id<#delegate#> delegate; @property (nonatomic, copy) <#returnType#> (^<#Block#>)(<#parType#>);
單例適合全局管理狀態或者事件的場景。一旦建立,對象的指針保存在靜態區,單例對象在堆內存中分配的內存空間只有程序銷燬的時候纔會釋放。基於這種特色,那麼咱們相似 UIApplication 對象,須要全局訪問惟一一個對象的狀況才適合單例,或者訪問頻次較高的狀況。咱們的功能模塊的生命週期確定小於 App 的生命週期,若是多個單例對象的話,勢必 App 的開銷會很大,糟糕的狀況系統會殺死 App。若是以爲非要用單例比較好,那麼注意須要在合適的場合 tearDown 掉。shell
單例的使用場景歸納以下:緩存
+ (instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //because has rewrited allocWithZone use NULL avoid endless loop lol. _sharedInstance = [[super allocWithZone:NULL] init]; }); return _sharedInstance; } + (id)allocWithZone:(struct _NSZone *)zone { return [TestNSObject sharedInstance]; } + (instancetype)alloc { return [TestNSObject sharedInstance]; } - (id)copy { return self; } - (id)mutableCopy { return self; } - (id)copyWithZone:(struct _NSZone *)zone { return self; }
推薦以 _
開頭,寫在 .m 文件中。例如 NSString * _somePrivateVariable安全
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath; - (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
- (instancetype)init { self = [super init]; if (self) { <#statements#> } return self; } - (void)doHomework:(NSString *)name period:(NSInteger)second score:(NSInteger)score;
//good - (instancetype)initWithAge:(NSInteger)age name:(NSString *)name; - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; //bad - (instancetype)initWithAge:(NSInteger)age andName:(NSString *)name; - (void)tableView:(UITableView *)tableView :(NSIndexPath *)indexPath;
.m
文件中的私有方法須要在頂部進行聲明文件基本上就是併發
//___FILEHEADER___ #import "___FILEBASENAME___.h" /*ViewController*/ /*View&&Util*/ /*model*/ /*NetWork InterFace*/ /*Vender*/ @interface ___FILEBASENAMEASIDENTIFIER___ () @end @implementation ___FILEBASENAMEASIDENTIFIER___ #pragma mark - life cycle - (void)viewWillAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewDidLoad { [super viewDidLoad]; self.title = <#value#>; } - (void)viewWillDisappear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidAppear:animated]; } #ifdef DEBUG - (void)dealloc { NSLog(@"%s",__func__); } #endif #pragma mark - public Method #pragma mark - private method #pragma mark - event response #pragma mark - UITableViewDelegate #pragma mark - UITableViewDataSource //...(多個代理方法依次往下寫) #pragma mark - getters and setters @end
command+option+/
。三個快捷鍵解決。按需在旁邊對方法進行說明解釋、返回值、參數的說明和解釋//
。採用 A.B.C 三位數字命名,好比:1.0.2,當有更新的狀況下按照下面的依據app
版本號 | 右說明對齊標題 | 示例 |
---|---|---|
A.b.c | 屬於重大內容的更新 | 1.0.2 -> 2.0.0 |
a.B.c | 屬於小部份內容的更新 | 1.0.2 -> 1.1.1 |
a.b.C | 屬於補丁更新 | 1.0.2 -> 1.0.3 |
咱們知道了平時在使用 Xcode 開發的過程當中使用的系統提供的代碼塊所在的地址和新建控制器、模型、view等的文件模版的存放文件夾地址後,咱們就能夠設想下咱們是否能夠定製本身團隊風格的控制器模版、是否能夠打造和維護本身團隊的高頻使用的代碼塊?less
答案是能夠的。
Xcode 代碼塊的存放地址:~/Library/Developer/Xcode/UserData/CodeSnippets
Xcode 文件模版的存放地址:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/File Templates/
@property (nonatomic, weak) id<<#delegate#>> delegate;
,你輸入 Property_block 就會出來 @property (nonatomic, copy) <#returnType#> (^<#Block#>)(<#parType#>);
咱們能夠將屬性、控制器生命週期方法、單例構造一個對象的方法、代理方法、block、GCD、UITableView 懶加載、UITableViewCell 註冊、UITableView 代理方法的實現、UICollectionVIew 懶加載、UICollectionVIewCell 註冊、UICollectionView 的代理方法實現等等組織爲 codesnippets
封裝好 codesnippets 以後團隊除了你編寫這個項目的人如何使用?如何知道是否有這個代碼塊?
方案:先在團隊內召開代碼規範會議,你們都統一知道這個事情在。以後你們共同維護 codesnippets。用法見下
屬性:經過 Property_類型 開頭,回車鍵自動補全。好比 Strong 類型,編寫代碼經過 Property_Strong 回車鍵自動補全成以下格式
@property (nonatomic, strong) <#Class#> *<#object#>;
方法:以 Method_關鍵詞 回車鍵確認,自動補全。好比 Method_UIScrollViewDelegate 回車鍵自動補全成 以下格式
#pragma mark - UIScrollViewDelegate - (void)scrollViewDidScroll:(UIScrollView *)scrollView { }
各類常見的 Mark:以 Mark_關鍵詞 回車確認,自動補全。好比 Method_MethodsGroup 回車鍵自動補全成 以下格式
#pragma mark - life cycle #pragma mark - public Method #pragma mark - private method #pragma mark - event response #pragma mark - UITableViewDelegate #pragma mark - UITableViewDataSource #pragma mark - getters and setters
封裝好 codesnippets 以後團隊內如何統一?想到一個方案,能夠將團隊內的 codesnippets 共享到 git,團隊內的其餘成員再從雲端拉取同步。這樣的話團隊內的每一個成員均可以使用最新的 codesnippets 來編碼。
編寫 shell 腳本。幾個關鍵步驟:
咱們觀察系統文件模版的特色,和在 Xcode 新建文件模版對應。
因此咱們新建 Custom 文件夾,將系統 Source 文件夾下面的 Cocoa Touch Class.xctemplate 複製到 Custom 文件夾下。重命名爲咱們須要的名字,我這裏以「Power」爲例
進入 PowerViewController.xctemplate/PowerViewControllerObjective-C
修改 ___FILEBASENAME___.h
和 ___FILEBASENAME___.m
文件內容
在替換 .h 文件內容的時候後面改成 UIViewController,否則其餘開發者新建文件模版的時候出現的不是 UIViewController 而是咱們的 PowerViewController
修改 TemplateInfo.plist
思考:
如何使用
商量好一個標識(「Power」)。好比我新建了單例、控制器、Model、UIView4個模版,都覺得 Power 開頭。
如何共享
以 shell 腳本爲工具。使用腳本將 git 雲端的代碼模版同步到本地 Xcode 文件夾對應的位置就可使用了。關鍵步驟:
chmod +x ./syncSnippets.sh // 爲腳本設置可執行權限 chmod +x ./uploadMySnippets.sh // 爲腳本設置可執行權限 ./syncSnippets.sh // 同步git雲端代碼塊和文件模版到本地 ./uploadMySnippets.sh //將本地的代碼塊和文件模版同步到雲端
不斷完善中。你們有好用或者不錯的代碼塊或者文件模版但願參與到這個項目中來,爲咱們開發效率的提高添磚加瓦、貢獻力量
目前新建了大概58個代碼段和6個類文件模版(UIViewController控制器帶有方法組、模型、線程安全的單例模版、帶有佈局方法的UIView模版、UITableViewCell、UICollectionViewCell模版)
shell 腳本基本有每一個函數和關鍵步驟的代碼註釋,想學習 shell 的人能夠看看代碼。代碼傳送門