1. 目錄
[TOC]
2. 修訂信息
版本 | 時間 | 修訂人 | 修訂內(nèi)容 |
---|---|---|---|
1.0 | 2016-03-28 | 麥志泉 | 創(chuàng)建文檔 |
3. 概述
為幫助開發(fā)者實現(xiàn)代碼的優(yōu)美與一致性、可讀性和簡潔性逃贝,
本人編寫了Swift編程規(guī)范指南,包含命名盟迟、空格秋泳、注釋、類和結(jié)構(gòu)體攒菠、
函數(shù)聲明迫皱、閉包表達(dá)式、類型辖众、控制流卓起、分號等。
4. 規(guī)范指南
4.1 命名(Naming)
使用駝峰式的描述性命名方式凹炸,為類戏阅,方法,變量等命名啤它。類名的首字母應(yīng)該大寫奕筐,而方法和變量的首字母使用小寫字符舱痘。
推薦做法:
private let maximumWidgetCount = 100
class WidgetContainer {
var widgetButton: UIButton
let widgetHeightPercentage = 0.85
}
不推薦做法:
let MAX_WIDGET_COUNT = 100
class app_widgetContainer {
var wBut: UIButton
let wHeightPct = 0.85
}
對于函數(shù)和初始化方法,推薦對所有的參數(shù)進(jìn)行有意義的命名离赫,
除非上下文已經(jīng)非常清楚芭逝。如果外部參數(shù)命名可以使得函數(shù)調(diào)用更加可讀,
也應(yīng)該把外部參數(shù)命名包含在內(nèi)渊胸。
func dateFromString(dateString: String) -> NSDate
func convertPointAt(#column: Int, #row: Int) -> CGPoint
func timedAction(#delay: NSTimeInterval, perform action: SKAction) -> SKAction!
// 調(diào)用方式如下:
dateFromString("2014-03-14")
convertPointAt(column: 42, row: 13)
timedAction(delay: 1.0, perform: someOtherAction)
對于方法來說旬盯,參照標(biāo)準(zhǔn)的蘋果慣例,方法命名含義要引用到第一個參數(shù):
class Guideline {
func combineWithString(incoming: String, options: Dictionary?) { ... }
func upvoteBy(amount: Int) { ... }
}
4.2 枚舉(Enumerations)
使用首字母大寫的駝峰命名規(guī)則來命名枚舉值:
enum Shape {
case Rectangle
case Square
case Triangle
case Circle
}
4.3 文章(Prose)
當(dāng)我們在文章中(教程翎猛,圖書胖翰,注釋等)需要引用到函數(shù)時,需要從調(diào)用者的視角考慮切厘,包含必要的參數(shù)命名萨咳,或者使用_表示不需要命名的參數(shù)。
從你自身實現(xiàn)的init中調(diào)用convertPointAt(column:row:)迂卢。
如果你調(diào)用dateFromString(_:),需要保證你提供的輸入字符串格式是”yyyy-MM-dd”某弦。
如果你需要在viewDidLoad()中調(diào)用timedAction(delay:perform:),記得提供調(diào)整后的延遲值和需要處理的動作而克。
你不能直接調(diào)用數(shù)據(jù)源方法tableView(_:cellForRowAtIndexPath:)
當(dāng)你遇到疑問時,可以看看Xcode在jump bar中是如何列出方法名的 —— 我們的風(fēng)格與此匹配怔毛。
4.4 類的前綴(Class Prefixes)
Swift類型自動被模塊名設(shè)置了名稱空間员萍,所以你不需要加一個類的前綴。如果兩個來自不同模塊的命名沖突了拣度,你可以附加一個模塊名到類型命名的前面來消除沖突碎绎。
import SomeModule
let myClass = MyModule.UsefulClass()
4.5 空格(Spacing)
使用Xcode默認(rèn)配置的數(shù)字就是
- 方法定義的大括號或者其他大括號(if/else/switch/while等)- 一般都放在定義名稱的同一行,
并且使用一個新的行來結(jié)束抗果。
- 提示:你可以通過以下方法重新進(jìn)行縮進(jìn):選擇一些代碼(或者使用?A選擇所有)筋帖,然后按Control-I(或者點擊菜單欄 Editor\Structure\Re-Indent)。一些Xcode模板代碼使用的縮進(jìn)是4個空格冤馏,所以這種方法可以很好的修復(fù)縮進(jìn)日麸。
推薦做法:
if user.isHappy {
// Do something
} else {
// Do something else
}
4.6 注釋(Comments)
枚舉注釋:
/**
證件印
- MainLand: 中國大陸
- HKorMacao: 香港澳門地區(qū)
- Taiwan: 臺灣
- Oversea: 海外
*/
enum IdcardAreaType: String {
case MainLand = "1"
case HKorMacao = "2"
case Taiwan = "3"
case Oversea = "4"
}
方法注釋:
/**
向下取第幾位小數(shù)
- parameter places: 第幾位小數(shù) ,1
15.96 * 10.0 = 159.6
floor(159.6) = 159.0
159.0 / 10.0 = 15.9
- returns: 15.96 = 15.9
*/
func f(places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return floor(self * divisor) / divisor
}
}
4.7 定義的案例(Example definition)
以下是一個風(fēng)格很好的類定義:
class Circle: Shape {
var x: Int, 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)
}
func describe() -> String {
return "I am a circle at \(centerString()) with an area of \(computeArea())"
}
override func computeArea() -> Double {
return M_PI * radius * radius
}
private func centerString() -> String {
return "(\(x),\(y))"
}
}
以上例子遵循了以下風(fēng)格規(guī)范:
- 指定屬性逮光、變量代箭、常量、參數(shù)定義或者其他定義的類型涕刚,在冒號后面嗡综,緊跟著一個空格,而不是把空格放在冒號前面杜漠。比如:x: Int和Circle: Shape极景。
- 如果能表示相同的目的和上下文察净,可以在同一行定義多個變量和結(jié)構(gòu)體。
- 縮進(jìn)getter盼樟,setter的定義和屬性觀察器的定義塞绿。
- 不需要添加internal這樣的默認(rèn)的修飾符。同樣的恤批,不需要在重寫一個方法時添加訪問修飾符异吻。
4.8 Self的使用(Use of Self)
為了保持簡潔,避免使用 self 關(guān)鍵詞喜庞,Swift 不需要使用 self 來訪問對象屬性和調(diào)用對象方法诀浪。
必須使用 self 來區(qū)分構(gòu)造器中屬性命名和參數(shù)命名,還有在閉包表達(dá)式中引用屬性值(編譯器需要區(qū)分):
class BoardLocation {
let row: Int, column: Int
init(row: Int, column: Int) {
self.row = row
self.column = column
let closure = {
println(self.row)
}
}
}
4.9 協(xié)議遵守(Protocol Conformance)
當(dāng)我們對一個類添加協(xié)議時延都,推薦使用一個單獨的類擴展來實現(xiàn)協(xié)議的方法雷猪。這可以保持協(xié)議相關(guān)的方法聚合在一起,同時也可以簡單的標(biāo)識出一個協(xié)議對應(yīng)類中需要實現(xiàn)哪些對應(yīng)的方法晰房。
同時求摇,別忘了添加// MARK:,注釋可以使得代碼組織的更好殊者!
推薦做法:
class MyViewcontroller: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewcontroller: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewcontroller: UIScrollViewDelegate {
// scroll view delegate methods
}
不推薦做法:
class MyViewcontroller: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
// all methods
}
4.9 計算屬性(Computed Properties)
為了保持簡潔与境,如果一個計算屬性是只讀的,請忽略掉get語句猖吴。只有在需要定義set語句的時候摔刁,才提供get語句。
推薦做法:
var diameter: Double {
return radius * 2
}
不推薦做法:
var diameter: Double {
get {
return radius * 2
}
}
4.10 函數(shù)聲明(Function Declarations)
保證短的函數(shù)定義在同一行中海蔽,并且包含左大括號:
func reticulateSplines(spline: [Double]) -> Bool {
// reticulate code goes here
}
在一個長的函數(shù)定義時共屈,在適當(dāng)?shù)牡胤竭M(jìn)行換行,同時在下一行中添加一個額外的縮進(jìn):
func reticulateSplines(spline: [Double], adjustmentFactor: Double,
translateConstant: Int, comment: String) -> Bool {
// reticulate code goes here
}
4.11 閉包表達(dá)式(Closure Expressions)
如果閉包表達(dá)式參數(shù)在參數(shù)列表中的最后一個時党窜,使用尾部閉包表達(dá)式拗引。給定閉包參數(shù)一個描述性的命名。
推薦做法:
UIView.animateWithDuration(1.0) {
self.myView.alpha = 0
}
UIView.animateWithDuration(1.0,
animations: {
self.myView.alpha = 0
},
completion: { finished in
self.myView.removeFromSuperview()
}
)
不推薦做法:
UIView.animateWithDuration(1.0, animations: {
self.myView.alpha = 0
})
UIView.animateWithDuration(1.0,
animations: {
self.myView.alpha = 0
}) { f in
self.myView.removeFromSuperview()
}
當(dāng)單個閉包表達(dá)式上下文清晰時幌衣,使用隱式的返回值:
attendeeList.sort { a, b in
a > b
}
4.12 類型(Types)
盡可能使用 Swift 原生類型矾削。Swift 提供到 Objective-C 類型的橋接,所以你仍然可以使用許多需要的方法泼掠。
推薦做法:
let width = 120.0 // Double
let widthString = (width as NSNumber).stringValue // String
不推薦做法:
let width: NSNumber = 120.0 // NSNumber
let widthString: NSString = width.stringValue // NSString
在Sprite Kit代碼中怔软,使用CGFloat可以使得代碼更加簡明,避免很多轉(zhuǎn)換择镇。
4.13 常量(Constants)
常量定義使用 let 關(guān)鍵字挡逼,變量定義使用 var 關(guān)鍵字,如果變量的值不需要改變腻豌,請盡量使用 let 關(guān)鍵字家坎。
提示:一個好的技巧是嘱能,使用 let 定義任何東西,只有在編譯器告訴我們值需要改變的時候才改成 var 定義虱疏。
全局或類的成員常量命名前加k
//MARK: - 常量
let kMarketChartDataRefreshTime: NSTimeInterval = 60 //數(shù)據(jù)刷新間隔
let kMarketDataRefreshTime: NSTimeInterval = 4 //數(shù)據(jù)刷新間隔
4.14 可選類型(Optionals)
當(dāng)nil值是可以接受的時候時惹骂,定義變量和函數(shù)返回值為可選類型(?)。
當(dāng)你確認(rèn)變量在使用前已經(jīng)被初始化時做瞪,使用!來顯式的拆包類型对粪,比如在viewDidLoad中會初始化subviews。
當(dāng)你訪問一個可選值時装蓬,如果只需要訪問一次或者在可選值鏈中有多個可選值時著拭,請使用可選值鏈:
self.textContainer?.textLabel?.setNeedsDisplay()
當(dāng)需要很方便的一次性拆包或者添加附加的操作時,請使用可選值綁定:
if let textContainer = self.textContainer {
// do many things with textContainer
}
當(dāng)我們命名一個可選變量和屬性時牍帚,避免使用諸如optionalString和maybeView這樣的命名儡遮,因為可選值的表達(dá)已經(jīng)在類型定義中了。
在可選值綁定中暗赶,直接映射原始的命名比使用諸如unwrappedView和actualLabel要好鄙币。
推薦做法:
var subview: UIView?
var volume: Double?
// later on...
if let subview = subview, volume = volume {
// do something with unwrapped subview and volume
}
不推薦做法:
var optionalSubview: UIView?
var volume: Double?
if let unwrappedSubview = optionalSubview {
if let realVolume = volume {
// do something with unwrappedSubview and realVolume
}
}
4.15 結(jié)構(gòu)體構(gòu)造器(Struct Initializers)
使用原生的 Swift 結(jié)構(gòu)體構(gòu)造器,比老式的幾何類(CGGeometry)的構(gòu)造器要好蹂随。
推薦做法:
let bounds = CGRect(x: 40, y: 20, width: 120, height: 80)
let centerPoint = CGPoint(x: 96, y: 42)
不推薦做法:
let bounds = CGRectMake(40, 20, 120, 80)
let centerPoint = CGPointMake(96, 42)
推薦使用結(jié)構(gòu)體限定的常量CGRect.infiniteRect,CGRect.nullRect等十嘿,來替代全局常量CGRectInfinite,CGRectNull等。對于已經(jīng)存在的變量糙及,可以直接簡寫成 .zeroRect详幽。
4.15 類型推斷(Type Inference)
推薦使用更加緊湊的代碼,讓編譯器能夠推斷出常量和變量的類型浸锨。除非你需要定義一個特定的類型(比如CGFloat和Int16),而不是默認(rèn)的類型版姑。
推薦做法:
let message = "Click the button"
let currentBounds = computeViewBounds()
var names = [String]()
let maximumWidth: CGFloat = 106.5
不推薦做法:
let message: String = "Click the button"
let currentBounds: CGRect = computeViewBounds()
var names: [String] = []
注意: 遵守這條規(guī)則意味選擇描述性命名比之前變得更加重要柱搜。
4.16 語法糖(Syntactic Sugar)
推薦使用類型定義簡潔的版本,而不是全稱通用語法剥险。
推薦做法:
var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?
不推薦做法:
var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>
4.17 控制流(Control Flow)
推薦循環(huán)使用for-in表達(dá)式聪蘸,而不使用for-condition-increment表達(dá)式。
推薦做法:
for _ in 0..<3 {
println("Hello three times")
}
for (index, person) in enumerate(attendeeList) {
println("\(person) is at position #\(index)")
}
不推薦做法:
for var i = 0; i < 3; i++ {
println("Hello three times")
}
for var i = 0; i < attendeeList.count; i++ {
let person = attendeeList[i]
println("\(person) is at position #\(i)")
}
4.17 ?類成員變量聲明
蘋果UIKit框架中的UIButton, UILabel等組件類表制,聲明最好以組件名開頭健爬,這樣在代碼提示中容易被檢索歸類
推薦做法:
/// MARK: - 成員變量
@IBOutlet var tableViewWealth: UITableView!
@IBOutlet var labelTotalAssetsTitle: UILabel!
@IBOutlet var labelTotalAssets: UILabel!
當(dāng)類使用到代理協(xié)議的設(shè)計模式時,delegate前要加weak
weak var delegate: BankListViewDelegate?