swift程式碼統一編碼規範
阿新 • • 發佈:2021-12-20
編碼規範
背景
隨著團隊擴大,人員增多。需要統一編碼規範規範
命名-明確的使用含義
- 請使用駝峰命名規則
- 首字母大寫
- 用統一的標識開頭:
YP
- 控制器
VC
結尾
- 命名應該具有標識性
- 不能使用拼音
- 不能使用過於簡單的縮寫
- 檢視命名
- 常規以View結尾:
UIContentView
- tableView的cell以TCell為字尾:
YPBaseTCell
- UICollectionView的cell以Cell為字尾:
YPBaseCCell
- vm
- 所有命名應該具有描述性
- 常規以View結尾:
- 屬性應該是一個名詞
- 區域性變數
- 需要遵守命名規範
- 使用具有代表意義的名詞
model
、item
、temp
、dataSource
//推薦
for i in dataSource {}
為了減少不必要的屬性申明
for model in models{}
models.foreach{$0.name = ""}
models.foreach{ model in
model.name = "1"
model.id = "2"
}
//不推薦
for a in dataSource {}
for m in models{}
models.foreach{ model in
model.name = ""
}
models.foreach{ f in
f.name = ""
f.id = ""
}
- 常量
- 常量的名字需要大寫首字母並保持駝峰:
KLastChoosedOccsInRecruitList
- 避免使用全域性常量,轉而使用結構體和類
- 常量的名字需要大寫首字母並保持駝峰:
KLastChoosedOccsInRecruitList
= "KLastChoosedOccsInRecruitList
"
}
//不推薦
let KLastChoosedOccsInRecruitList
= "KLastChoosedOccsInRecruitList
"
- 列舉
- 以enum結尾
- Case的命名
- 小寫字母開頭
- 名詞或者動詞
- 駝峰規則
- 型別
- 根據變數、引數、關聯型別的作用來命名,而不是基於它們的型別
- 協議
- 描述事物的協議,讀起來應該像名詞(例如,
Collection
) - 描述能力的協議,應該使用字尾
able
,ible
或ing
- 描述事物的協議,讀起來應該像名詞(例如,
- 協議方法,第一個未命名引數應該是委託資料來源
方法
- 方法或者函式名最好能在呼叫處形成符合語法規範的英語短語
- 省略無用的單詞。每個單詞都需要傳達出相應的關鍵資訊
- 為了使用起來更流暢,可以從第二個或者第三個引數開始降低命名要求,前提是這些引數不影響整個 API 的語義
- 工廠方法用
make
開頭:x.makeWidget(cogCount: 47)
- 構造器和工廠方法的第一個引數命名不應該考慮方法名,應該獨立命名,如:
x.makeWidget(cogCount: 47)
- 沒有副作用的方法和函式讀起來應該像名詞短語
x.distance(to: y)
,i.successor()
- 有副作用的方法和函式讀起來應該像祈使動詞
print(x)
,x.sort()
,x.append(y)
-
可變/不可變方法的命名要成對出現。一個可變方法通常都有一個不可變方法與之對應,二者的語義相近,區別在於前者更新例項,而後者返回一個新值
- 當一項操作恰好能夠被一個動詞描述時,使用動詞原形為可變方法命名;使用動詞的過去分詞 (ed) 或現在分詞 (ing) 為不可變方法命名
- 命名不可變方法,最好使用過去分詞(通常是增加字尾 “ed”)
- 如果由於動詞後面直接跟隨一個物件,無法新增 “ed” 時,使用現在分詞命名不可變方法,即字尾 “ing”
- 當一項操作恰好能夠被一個名詞描述時,使用名詞本身為不可變方法命名;使用名詞前加 “form” 的方式為可變方法命名。
-
對於返回值是布林型別的方法和屬性,讀起來應該像是對被呼叫物件的斷言,其使用場景是不可變方法。例如,
x.isEmpty
,line1.intersects(line2)
。
- 避免使用全域性函式,轉而使用方法和屬性。以下情況例外
- 沒有明顯的self:
min(x, y, z)
- 沒有明顯的self:
- 函式是不受限的範型函式:
print(x)
- 在特定的領域中已經有約定俗成函式語法在:
sin(x)
- 對於沒有引數的方法
註釋
/// 類註釋[會在程式碼提示中顯示]:使用者資訊模型 class YPUserInfoModel{ /// 屬性註釋[會在程式碼提示中顯示]:使用者id var id: String? /// 屬性註釋[會在程式碼提示中顯示]:使用者暱稱 var name: String? } //MARK: - 程式碼模組註釋[在檔案目錄中顯示] extension YPUserInfoModel{ /// 方法註釋[會在程式碼提示中顯示]:更新使用者暱稱 /// - Parameters: /// - userName: 使用者暱稱 /// - Returns: model func update(userName: String) -> Self{ //內部說明: 邏輯說明 name = userName } } class YPHomeListVC: UIViewController{ //MARK: 業務屬性 /// 操作型別 let operation: Operation = .normal /// 頁碼 var page: Int = 0 ... //MARK: UI屬性[懶載入] /// 頭檢視 lazy var headView: UIView = { let view = UIView() //coding return view }() /// 表格 lazy var tableView: UITableView = { let view = UITableView() //coding return view }() }- 所有的類必須新增類註釋
- 所有屬性必須加註釋
- 方法必須加註釋,方法中的引數和返回需要有註釋
- 方法內部,複雜邏輯需要新增邏輯說明
- 方法中的引數需要新增明確的作用說明,如果有返回值也需要說明
- 複雜邏輯 註釋在程式碼處
程式碼組織結構
目錄結構
- Main
- 標籤模組1
- Home
- View
- Cell
- Controller
- ViewModel
- View
- 功能模組1
- 。。。
- 功能模組2
- 。。。
- Home
- 標籤模組2
- 標籤模組3
- 。。。
- 標籤模組1
- Model
- Resource
- 標籤模組
- name.svg
- 標籤模組
控制器中列舉和結構體的宣告
訪問域
- 明確屬性、方法、類的訪問域:
private
、fileprivate
、internal
、public
和open
- 同訪問域的方法應該通過
extension
的程式碼塊進行整合【不合理】
- 只開放get的許可權
屬性申明
- 對於不需要修改的內容使用
let
程式碼
空格
- 等號前後需有空格
- if的判斷條件前後需有空格
換行
- 程式碼塊
寫法
- 應該使用 +=, -=, *=, /=
懶載入
- controller中的UI必須使用懶載入
- 懶載入的內部檢視 統一使用view,不要與其本身相同
- 請新增合適且明確的訪問域
- 在懶載入中不要直接
addSubView
addSubView
(view)
return view
}()
}
記憶體
Block
- 型別申明
weak 和 unowned
//推薦 let call: Call = {[weak self] in guard let weakSelf = self else {return} //coding } //不推薦 let call: Call = {[weak self] in guard let self = self else {return} //coding }podfile
- 接入的第三方庫,必須直接指定版本
彈窗
- fYPProgressHUD
- YPLableAlertView
- YPStateAlertView
MVVM
input、output、transform
為了減少不必要的屬性申明,在VC和VM的互動中。部分邏輯和 事件應該通過下面的方式進行互動 不支援在 Docs 外貼上 block f- VC不需要引用目標,例如提交方法、登入方法
VM中的Rx
- 使用let
- 避免對controller的引用,需要使用controller的時候,請用回撥和Rx的方式放在controller中
業務
網路庫
errCode
在業務場景中,建議不要直接使用字串,改用列舉型別 /// 推薦 if YPWhiteListEnum.paidIssue.rawValue == response.errCode {// "paid_issue" 付費釋出提示 paidSendAlert(response: response) } /// 不推薦 if "integral_lack" == response.errCode {// 付費釋出積分不足 integralLackAlert(response: response) }推薦
推薦使用isEmpty
//推薦 "sadasdsa".isEmpty [1,2].isEmpty //不推薦 "sadasdsa".count == 0 [1,2].count == 0禁止強制解包
//推薦 guard let value = values2 as? String else {return} //不推薦 let value = value2 as! String陣列取值,需要判斷陣列是否下標越界
//推薦 let source: [String] = ["1"] if source.count > 1{ let value: String = source[1] } let value: String? = source.safe(idx: 1) //不推薦 let value: String = source[1]獲取系統版本號,禁止強制直接轉數值型別
let versionString = "14.2.1" //推薦 let versions:[Int] = versionString.components(separatedBy: '.').map{Int($0) ?? 0} //不推薦 let vaersion: CGFloat = CGFloat(versionString)不推薦使用public、fileprivate等修飾符 修飾cextension擴充套件
//推薦 extension YPHomeViewModel{ fileprivate func medthod(){} fileprivate func medthod(){} } //不推薦 fileprivate extension YPHomeViewModel{ func medthod(){} func medthod(){} }SnpKit
- 約束的程式碼儘量精簡
- 適配劉海屏
- 路由