版本記錄
| 版本號(hào) | 時(shí)間 |
|---|---|
| V1.0 | 2018.12.4 |
前言
Swift是編寫軟件的絕佳方式,無(wú)論是用于手機(jī),臺(tái)式機(jī),服務(wù)器還是其他任何運(yùn)行代碼的軟件。它是一種安全,快速,交互式的編程語(yǔ)言,它將現(xiàn)代語(yǔ)言思維的最佳結(jié)合與來(lái)自更廣泛的Apple工程文化的智慧和來(lái)自開源社區(qū)的各種貢獻(xiàn)相結(jié)合。編譯器針??對(duì)性能進(jìn)行了優(yōu)化,語(yǔ)言針對(duì)開發(fā)進(jìn)行了優(yōu)化,而不會(huì)對(duì)其進(jìn)行任何影響。
Swift對(duì)新程序員很友好。它是一種工業(yè)級(jí)編程語(yǔ)言,與腳本語(yǔ)言一樣富有表現(xiàn)力和樂趣。在playground上編寫Swift代碼可以讓您試驗(yàn)代碼并立即查看結(jié)果,而無(wú)需構(gòu)建和運(yùn)行應(yīng)用程序的開銷。
正文
正確性
力爭(zhēng)讓代碼沒有編輯警告(warning)。這個(gè)規(guī)則下衍生出了許多決定,如:使用#selector方式,而不是直接使用字符串。
注意:由于iOS系統(tǒng)版本升級(jí),同時(shí)App支持版本的問(wèn)題,合理選擇正確的未失效方法,可消除部分編譯警告。
命名
描述性和一致性的命名會(huì)讓代碼更加的易讀、易懂。命名請(qǐng)遵循一下規(guī)則:
- 追求調(diào)用方的清晰性
- 優(yōu)先使用更清晰的命名,而不是更簡(jiǎn)潔的命名
- 使用駝峰樣式
- 類型、協(xié)議名首字符大寫,其他的都首字母小寫
- 包含所有需要的單詞,省略不必要的
- 使用基于角色的命名,而不是基于類型的
- 工廠方法使用make開頭
- 對(duì)方法的命名
- 不要使用生僻的單詞
- 通常不要用縮寫
- 選用好的參數(shù)名來(lái)起到描述的作用
類前綴
Swift中的類型自動(dòng)使?了其所在的模塊作為命名空間,所以不必給類型加
前綴。如果來(lái)?不同模塊的類型名字沖突,可以顯示的使?模塊名作為調(diào)?前綴來(lái)避免沖突。
建議
import SomeModule
import OtherModule
let someUsefulClass = SomeModule.UsefulClass()
let otherUsefulClass = OtherModule.UsefulClass()
代理
當(dāng)定義一個(gè)代理?法時(shí),第一個(gè)匿名參數(shù)應(yīng)該是代理的源對(duì)象。( UIKit 中有許多這樣的的例子)
建議
func numberOfSections(in tableView: UITableView) -> Int
使?可類型推導(dǎo)的上下?文
利用好編譯器?的類型推斷特性,來(lái)寫出簡(jiǎn)短、清晰的代碼。
建議
self.collectionView.backgroundColor = .white
泛型
泛型參數(shù)應(yīng)當(dāng)使?具有描述性的駝峰樣式來(lái)命名。當(dāng)泛型參數(shù)不具有
明確的關(guān)系或??時(shí),可使??個(gè)?寫的字母表示即可。如: T , U , V
使?的語(yǔ)?
應(yīng)使?用美式英語(yǔ)的拼寫?方式以匹配Apple的API,應(yīng)盡量保持命名的可讀性,不應(yīng)該?多含義且有相反或者混淆意思的單詞。
建議
let color = "white"
不建議
let colour = "white"
代碼組織
盡可能的使?擴(kuò)展(extensions)來(lái)解耦你的代碼,將代碼劃分到不同的擴(kuò)展模塊中,每個(gè)擴(kuò)展盡量使用// MARK: -開頭,用以來(lái)更好的區(qū)分?jǐn)U展。
協(xié)議的遵守
具體來(lái)講,當(dāng)讓一個(gè)Model遵守某個(gè)協(xié)議時(shí),推薦添加一個(gè)獨(dú)立的Model擴(kuò)展(extensions)來(lái)遵守該協(xié)議。這樣使得相關(guān)的協(xié)議?法能組織在一起。
對(duì)于 UIKit 的視圖控制器(view controllers),可以考慮將?生命周期(LifeCycle)相關(guān)、?定義訪問(wèn)器( custom accessors )、 IBAction 獨(dú)?不同的到類擴(kuò)展中。
建議
// MARK: - UITableViewDelegate
extension XXViewController: UITableViewDataSource, UITableViewDelegate
?用的代碼
?用的代碼包括Xcode產(chǎn)?生的模板代碼、占位的注釋等、?法的默認(rèn)實(shí)現(xiàn)僅僅是調(diào)用 super 等,這些都應(yīng)當(dāng)移除掉。
建議
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.dataList.count
}
不建議
// 該方法什么都沒干,存在反而會(huì)增加小伙伴的閱讀量
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
減小引入
保存最小的引入(imports)。例如, 當(dāng)只使用Foundation時(shí),不要引?入UIKit。
空格
- 代碼折行使用4個(gè)空格
- 方法的大括號(hào)和其他大括號(hào)(
if/else/switch/while),其左括號(hào)必須要和語(yǔ)句在同一個(gè)行,并且右括號(hào)要換行;
建議
if XXX == 1 {
// do something
} else {
// do something else
}
- 變量類型和冒號(hào)(
:)之間保留一個(gè)空格;
建議
let cellHeight: CGFloat = 73.5
- 返回值標(biāo)記(
->)兩側(cè)各保留一個(gè)空格;
建議
func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect
- 各個(gè)方法之間必須有一個(gè)空格,這使得代碼視覺上更清晰;
- 方法的實(shí)現(xiàn)中,應(yīng)當(dāng)適當(dāng)?shù)奶砑涌招衼?lái)劃分功能。過(guò)多的空行意味著應(yīng)該拆分這些功能到不同的方法中,通過(guò)這樣來(lái)避免一個(gè)巨大的方法;
- 通常冒號(hào)(:)的左邊應(yīng)當(dāng)沒有空格,而在右邊有一個(gè)空格。當(dāng)然這個(gè)是有例外的,如:三目運(yùn)算符、空字段、無(wú)參數(shù)方法等;
建議
var delegate: UICollectionViewDelegate?
注釋
- 給方法或者屬性添加注釋,可以使用
option + command + /來(lái)讓Xcode自動(dòng)生成,也可以使用MARK: -等;
option + command + /效果如下
/// <#Description#>
///
/// - Parameters:
/// - pageNo: <#pageNo description#>
/// - lon: <#lon description#>
/// - lat: <#lat description#>
/// - state: <#state description#>
/// - responseComplete: <#responseComplete description#>
func requstNetData(_ pageNo: Int,
_ lon: Double,
_ lat: Double,
_ state: Int,
_ responseComplete: HttpComplete) {
}
- 給關(guān)鍵邏輯添加一些局部注釋,單行注釋請(qǐng)用
//; - 注釋要保持最新狀態(tài);
類與結(jié)構(gòu)體
結(jié)構(gòu)體(struct)是值類型,當(dāng)事物不具有唯一性時(shí),使用結(jié)構(gòu)體。
類是引用類型,當(dāng)事物具有唯一性或者有明確的生命周期時(shí),使用類。
以下是一個(gè)類的定義
class Circle: Shape {
var x: Int
var y: Int
var radius: Double
var diameter: Double {
get {
return radius * 2
}
set {
radius = newValue / 2
}
}
init(x: Int, y: Int, radius: Double) {
self.x = x
self.y = y
self.radius = radius
}
convenience init(x: Int, y: Int, diameter: Double) {
self.init(x: x, y: y, radius: diameter / 2)
}
override func area() -> Double {
return Double.pi * radius * radius
}
}
extension Circle: CustomStringConvertible {
var description: String {
return "center = \(_centerString) area = \(area())"
}
private var _centerString: String {
return "(\(x),\(y))"
}
}
使用self
在Swift中,可以通過(guò)利用好編譯器的類型推斷特性省略self來(lái)訪問(wèn)一個(gè)獨(dú)享的屬性或者方法。但是為了消除使用的歧義,建議使用self來(lái)訪問(wèn)。
計(jì)算屬性
為了簡(jiǎn)潔性,如果?個(gè)計(jì)算屬性是只讀(read-only)的,那么應(yīng)省略 get { ... } 語(yǔ)句。get { ... }語(yǔ)句只在計(jì)算屬性是讀寫( read-write )時(shí),才要求使?。
建議
var area: Double {
return width * height
}
使用final標(biāo)記
出于某些原因,你可能不希望一個(gè)類被繼承,這時(shí)你可以將其標(biāo)記為final來(lái)表示它不不能被繼承。
例如:一個(gè)單例,可能就不希望被繼承。
函數(shù)聲明
- 將簡(jiǎn)短的函數(shù)聲明保留在一行中,包括左括號(hào);
建議
func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?
- 無(wú)返回值的函數(shù)可以省略(
-> Void)返回值;
建議
func register(_ nib: UINib?, forCellWithReuseIdentifier identifier: String)
- 參數(shù)較多的函數(shù)可以像
Objective-C中一樣進(jìn)行折行處理;
建議
func foo(arg1: Int,
arg2: Double,
arg3: String,
arg4: [Bool],
arg5: () -> Void) {
/* code goes here */
}
閉包表達(dá)式
當(dāng)參數(shù)列表末尾只有一個(gè)閉包參數(shù)時(shí),才應(yīng)該使用尾隨閉包語(yǔ)法。
對(duì)于使?閉包的鏈?zhǔn)秸{(diào)?,應(yīng)當(dāng)讓代碼更清晰、更易讀??梢越柚崭?spacing)、換?(line breaks)和匿名參數(shù)(anonymous arguments)等?法來(lái)讓代碼更清晰、更易讀,但這都依賴于你的選擇。
類型
應(yīng)盡量使用Swift的原生類型,當(dāng)然Swift提供了對(duì)Objective-C類型的橋接方法,你可以使用Objective-C的所有方法。
建議
let width = 120.0 // Double
let widthString = (width as NSNumber).stringValue
常量
常量使用關(guān)鍵字let定義,變量使用關(guān)鍵字var定義。除非值可變,否則都應(yīng)該用關(guān)鍵字let定義。
在一個(gè)類型的內(nèi)容,通過(guò)關(guān)鍵字static let來(lái)定義靜態(tài)常量,這樣可以更好的組織這些靜態(tài)變量。
建議
enum Math {
static let e = 2.718281828459045235360287
static let pi = 3.14159265358979323846264
}
類內(nèi)部的靜態(tài)方法和屬性,有點(diǎn)類似于全局方法和屬性。但應(yīng)盡量避免使用全局方法和屬性。有一些例外情況,比如當(dāng)使用runtime的objc_getAssociatedObjec()函數(shù)時(shí),需要定義一個(gè)全局的key來(lái)作為參數(shù)。
可選類型
當(dāng)使用?來(lái)定義可選類型時(shí),表明它可以接受為nil的值;
當(dāng)使用!來(lái)定義可選類型時(shí),表明它可以接受為nil的值,但必須保證在使用它時(shí),值不為nil;
使用可選綁定來(lái)一次性解包單個(gè)或多個(gè)可選類型值
類型推導(dǎo)
對(duì)于局部變量,盡量使用類型推導(dǎo)來(lái)讓代碼更緊湊。而對(duì)于成員變量來(lái)說(shuō),應(yīng)盡量不要使用類型推導(dǎo)來(lái)讓類的定義更清晰。
語(yǔ)法糖
利用語(yǔ)法糖,使用更簡(jiǎn)短的聲明方式
內(nèi)存管理
可以通過(guò)使用weak和unowned來(lái)避免循環(huán)引用,但也可以直接使用值類型(struct,enum)來(lái)避免循環(huán)引用。
可以通過(guò)guard let的形式來(lái)產(chǎn)生strongSelf
建議
guard let sSelf = self else { return }
訪問(wèn)控制
一般來(lái)說(shuō),被標(biāo)記為private、fileprivate的屬性或方法都應(yīng)以下劃線(_)開頭。例外情況是,當(dāng)標(biāo)記被修飾為private(set)、fileprivate(set)時(shí),不需要下劃線(_)開頭,因?yàn)樗麄兌际强稍L問(wèn)的屬性,只是他們都是只讀屬性而已。
建議
private var _isEnabled: Bool
fileprivate var _isClosed: Bool
private func _foo() {
// code goes here
}
fileprivate func _bar() {
// code goes here
}
private(set) var isEnabled: Bool
fileprivate(set) var isClosed: Bool
一般將訪問(wèn)控制標(biāo)記放在聲明的最前面,但例外情況中,當(dāng)有屬性標(biāo)記@IBAction、@IBOutlet、@discardableResult、@objc時(shí),需要將屬性標(biāo)記放在最前面。
建議
@IBOutlet private var _titleLab: UILabel!
控制流
優(yōu)先使用for-in的方式而不是while
建議
for (index, person) in attendeeList.enumerated() {
print("\(person) is at position #\(index)")
}
使用Guard語(yǔ)句
通過(guò)使用guard來(lái)避免使用if時(shí)代碼塊的深度嵌套問(wèn)題
建議
func check(phone: String?, name: String?, age: Int) -> Bool {
// 把對(duì)phone、name、age的判斷放到?一個(gè)guard?里里,更更簡(jiǎn)潔
guard
let ph = phone, ph.count > 0,
let nm = name, nm.count > 0,
age > 0 else {
return false
}
return true
}
分號(hào)
在Swift中不要求必須加分號(hào),一般情況下你不需要使用分號(hào)。只有當(dāng)你希望將多行代碼寫在一行時(shí),才需要加分號(hào)來(lái)斷句。
圓括號(hào)
一般情況下,在類型if條件、for循環(huán)等控制語(yǔ)句中不需要加圓空號(hào)。只有當(dāng)你在進(jìn)行數(shù)學(xué)運(yùn)算時(shí),希望代碼可讀性更高時(shí)才需要適當(dāng)?shù)奶砑訄A括號(hào)。
建議
let result = ((x * y) + 2) / h