> 原文出處:http://letsswift.com/2014/07/swift-style-guide/
[TOC]
## 語言
使用美式英語拼寫以匹配蘋果公司的API
優選:
~~~
var color = "red"
~~~
不建議使用:
~~~
var colour = "red"
~~~
## [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E9%97%B4%E9%9A%94)間隔
* 使用2個空格進行縮進而不是使用Tab,這樣可以節省空格,阻止換行。確保在Xcode的配置項中進行了設置。
* 方法的花括號以及其它花括號(`if`/`else`/`switch`/`while`等等)總是跟語句在同一行開始,但是在新的一行中結束。
優選:
~~~
if user.isHappy {
//Do something
} else {
//Do something else
}
~~~
不建議使用:
~~~
if user.isHappy
{
//Do something
}
else {
//Do something else
}
~~~
* 方法之間應該總是用一空白行進行分隔以提高視覺以及結構上的清晰度。方法中的空白符用來隔離功能塊,但是如果一個方法中存在太多這種功能塊時,通常也意味著你需要將它重構為多個方法了。
## [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E6%B3%A8%E9%87%8A)注釋
* 在需要的時候使用注釋說明一塊代碼為什么這么做。注釋必須時刻跟進代碼,不然刪了得了。
* 因為代碼應該盡可能的自文檔化,所以避免在代碼中使用成塊的注釋。例外:該規則不適用與用于生成文檔的成塊注釋。
## [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E5%91%BD%E5%90%8D)命名
使用駝峰法為類、方法、變量等等取一個描述性強的名字。模塊范圍的類名以及常量名稱要以大寫字母開頭,而方法名跟變量名則應該以小寫字母開頭。
優選:
~~~
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
}
~~~
對于普通函數以及構造函數名稱,除非上下文含義非常清楚,對所有的參數都加以命名是更為推薦的做法。如果外部參數名稱可以使得函數調用更具有可讀性,那么請帶上它。
~~~
func dateFromString(dateString: NSString) -> NSDate
func convertPointAt(#column: Int, #row: Int) -> CGPoint
func timedAction(#delay: NSTimeInterval, perform action: SKAction) -> SKAction!
// 會被這樣調用
dateFromString("2014-03-14")
convertPointAt(column: 42, row: 13)
timedAction(delay: 1.0, perform: someOtherAction)
~~~
對于方法,遵循蘋果公司的命名標準,在方法名中提及第一個參數:
~~~
class Guideline {
func combineWithString(incoming: String, options: Dictionary?) { ... }
func upvoteBy(amount: Int) { ... }
}
~~~
在所有提及到[函數](http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=e179f97ed1e2c39&k=%BA%AF%CA%FD&k0=%BA%AF%CA%FD&kdi0=0&luki=9&n=10&p=baidu&q=17042170_cpr&rb=0&rs=1&seller_id=1&sid=392c1eed979f170e&ssp2=1&stid=0&t=tpclicked3_hc&td=1915056&tu=u1915056&u=http%3A%2F%2Fletsswift%2Ecom%2F2014%2F07%2Fswift%2Dstyle%2Dguide%2F&urlid=0)的內容中(包括[教程](http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=e179f97ed1e2c39&k=%BD%CC%B3%CC&k0=%BD%CC%B3%CC&kdi0=0&luki=4&n=10&p=baidu&q=17042170_cpr&rb=0&rs=1&seller_id=1&sid=392c1eed979f170e&ssp2=1&stid=0&t=tpclicked3_hc&td=1915056&tu=u1915056&u=http%3A%2F%2Fletsswift%2Ecom%2F2014%2F07%2Fswift%2Dstyle%2Dguide%2F&urlid=0),書以及評論),請從調用者的視角進行考慮,將所有的必要參數名都包含進來:
~~~
dateFromString()函數真是太棒了。
在你的init()方法中調用convertPointAt(column:, row:)。
timedAction(delay:, perform:)的返回值可能為nil。
Guideline對象只有兩個方法:combineWithString(options:)跟upvoteBy()。
你不應該直接調用數據源方法tableView(cellForRowAtIndexPath:)。
~~~
### [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E7%B1%BB%E5%89%8D%E7%BC%80)類前綴
Swift中的類型會自動加入包含它們的模塊的命名空間。所以即使是為了最小化命名沖突的可能性,前綴也是不必要的。如果來自于不同模塊的兩個名稱沖突了,可以通過在名稱前面加上模塊名以消除歧義:
~~~
import MyModule
var myClass = MyModule.MyClass()
~~~
不應該在自己創建的類型上加前綴。
如果需要將Swift類型暴露在Objective-C環境中使用,請按照以下方式提供合適的前綴(前綴的命名請參考[Objective-C風格指南](https://github.com/raywenderlich/objective-c-style-guide)):
~~~
@objc (RWTChicken) class Chicken {
...
}
~~~
## [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E5%88%86%E5%8F%B7)分號
Swift中,每條語句后的分號都不是必需的。只有在一行中有多條語句時才需要添加上分號。
請不要在一行中寫上用分號隔開的多條語句。
這條規則的唯一例外就是`for-conditional-increment`結構,該結構中分號是必需的。不過,請盡可能地使用另外一種結構,`for-in`循環。
優選:
~~~
var swift = "not a scripting language"
~~~
不建議使用:
~~~
var swift = "not a scripting language";
~~~
請注意:Swift與JavaScript不同, 在后者中省略分號[通常是不安全的](http://stackoverflow.com/questions/444080/do-you-recommend-using-semicolons-after-every-statement-in-javascript)。
## [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E7%B1%BB%E4%B8%8E%E7%BB%93%E6%9E%84%E4%BD%93)類與結構體
下面的代碼是一個很有標準范兒的類定義,請參考:
~~~
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 (\(x),\(y)) with an area of \(computeArea())"
}
func computeArea() -> Double {
return M_PI * radius * radius
}
}
~~~
上面的例子闡述了這么幾個風格上的準則:
* 當為屬性、變量、常量、參數[聲明](http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=e179f97ed1e2c39&k=%C9%F9%C3%F7&k0=%C9%F9%C3%F7&kdi0=0&luki=1&n=10&p=baidu&q=17042170_cpr&rb=0&rs=1&seller_id=1&sid=392c1eed979f170e&ssp2=1&stid=0&t=tpclicked3_hc&td=1915056&tu=u1915056&u=http%3A%2F%2Fletsswift%2Ecom%2F2014%2F07%2Fswift%2Dstyle%2Dguide%2F&urlid=0)以及其它語句等定義類型時,而冒號的后面加上空格而不是前面,比如:`x: Int`跟`Circle: Shape`。
* 要對getter跟setter定義以及屬性觀察器進行縮進。
* 如果多個變量、結構有著同樣的目的或者上下文,在同一行上進行定義。
## [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#self)Self
考慮到在Swift中訪問一個對象的屬性或者調用它的方法并不需要使用`self`,所以請避免使用它。
需要使用`self`的唯一理由就是在初始化一個類或者結構體時,使用其在屬性名和參數之間加以區分:
~~~
class BoardLocation {
let row: Int, column: Int
init(row: Int,column: Int) {
self.row = row
self.column = column
}
}
~~~
## [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E5%87%BD%E6%95%B0%E5%A3%B0%E6%98%8E)函數聲明
保持函數聲明短小精悍,盡量在一行中完成[聲明](http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=e179f97ed1e2c39&k=%C9%F9%C3%F7&k0=%C9%F9%C3%F7&kdi0=0&luki=1&n=10&p=baidu&q=17042170_cpr&rb=0&rs=1&seller_id=1&sid=392c1eed979f170e&ssp2=1&stid=0&t=tpclicked3_hc&td=1915056&tu=u1915056&u=http%3A%2F%2Fletsswift%2Ecom%2F2014%2F07%2Fswift%2Dstyle%2Dguide%2F&urlid=0),同時還包含了開括號:
~~~
func reticulateSplines(spline: Double[]) -> Bool {
// reticulate code goes here
}
~~~
對于有著長長的參數的函數,請在適當的位置進行斷行且對后續行縮進一級:
~~~
func reticulateSplines(spline: Double[], adjustmentFactor: Double,
translateConstant: Int, comment: String) -> Bool {
// reticulate code goes here
}
~~~
## [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E9%97%AD%E5%8C%85)閉包
盡可能地使用尾閉包語法。在所有的情況下都需要給閉包參數一個描述性強的名稱:
~~~
return SKAction.customActionWithDuration(effect.duration) { node, elapsedTime in
// more code goes here
}
~~~
對于上下文清晰的單表達式閉包,使用隱式的返回值:
~~~
attendeeList.sort { a, b in
a > b
}
~~~
## [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E7%B1%BB%E5%9E%8B)類型
盡可能地使用Swift原生類型。Swift提供了對Objective-C的橋接所以在需要的時候仍然可以使用全部的Objective-C方法:
優選:
~~~
let width = 120.0 //Double
let widthString = width.bridgeToObjectiveC().stringValue //String
~~~
不建議使用:
~~~
let width: NSNumber = 120.0 //NSNumber
let widthString: NSString = width.stringValue //NSString
~~~
在Sprite Kit的代碼中,如果`CGFloat`可以避免過多的轉換而使得代碼簡潔明了,那么請用上它。
### [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E5%B8%B8%E9%87%8F)常量
常量通過`let`關鍵字定義,而變量使用`var`關鍵字定義。任何值如果是一個不變量,那么請使用`let`關鍵字恰如其分地定義它。最后你會發現自己喜歡使用`let`遠多于`far`。
Tip:有一個方法可以幫你符合該項規則,將所有值都定義成常量,然后編譯器提示的時候將其改為變量。
### [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#optionals)Optionals
在nil值可能出現的情況下,將變量跟[函數](http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=e179f97ed1e2c39&k=%BA%AF%CA%FD&k0=%BA%AF%CA%FD&kdi0=0&luki=9&n=10&p=baidu&q=17042170_cpr&rb=0&rs=1&seller_id=1&sid=392c1eed979f170e&ssp2=1&stid=0&t=tpclicked3_hc&td=1915056&tu=u1915056&u=http%3A%2F%2Fletsswift%2Ecom%2F2014%2F07%2Fswift%2Dstyle%2Dguide%2F&urlid=0)返回值的類型通過`?`定義成Optional。
只有在確定實例變量會在初始化之后才被使用的情況下,通過`!`將其定義為隱式解包類型(Implicitly Unwrapped Types),比如說會在`viewDidLoad`中被創建的子視圖。
在訪問一個Optional值時,如果該值只被訪問一次,或者之后需要連續訪問多個Optional值,請使用鏈式Optional語法:
~~~
myOptional?.anotherOne?.optionalView?.setNeedsDisplay()
~~~
對于需要將Optional值解開一次,然后進行多個操作的情況,使用Optional綁定更為方便:
~~~
if let view = self.optionalView {
// do many things with view
}
~~~
### [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD)類型推斷
Swift的編譯器可以推斷出變量跟常量的類型。可以通過類型別名(在冒號后面指出其類型)提供顯式類型,不過大多數情況下這都是不必要的。
保持代碼緊湊,然后讓[編譯器](http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=18&is_app=0&jk=e179f97ed1e2c39&k=%B1%E0%D2%EB%C6%F7&k0=%B1%E0%D2%EB%C6%F7&kdi0=0&luki=8&n=10&p=baidu&q=17042170_cpr&rb=0&rs=1&seller_id=1&sid=392c1eed979f170e&ssp2=1&stid=0&t=tpclicked3_hc&td=1915056&tu=u1915056&u=http%3A%2F%2Fletsswift%2Ecom%2F2014%2F07%2Fswift%2Dstyle%2Dguide%2F&urlid=0)推斷變量跟常量的類型。
優選:
~~~
let message = "Click the button"
var currentBounds = computeViewBounds()
~~~
不建議使用:
~~~
let message: String = "Click the button"
var currentBounds: CGRect = computeViewBounds()
~~~
注意:遵循這條準則意味著描述性強的名稱比之前更為重要了。
## [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E6%8E%A7%E5%88%B6%E6%B5%81)控制流
對于`for`循環,優選`for-in`風格而不是`for-condition-increment`風格:
優選:
~~~
for _ in 0..5 {
println("Hello five times")
}
for person in attendeeList {
// do something
}
~~~
不建議使用:
~~~
for var i = 0; i < 5; i++ {
println("Hello five times")
}
for var i = 0; i < attendeeList.count; i++ {
let person = attendeeList[i]
// do something
}
~~~
## [](https://github.com/raywenderlich/swift-style-guide/blob/master/zh_style_guide.md#%E7%AC%91%E8%84%B8)笑臉
笑臉對于raywenderlich.com來說是一個格外重要的風格特征。使用正確的笑臉可以表示出對某個主題的無窮盡的高興以及興奮程度。選用了`]`是因為它在ASCII藝術可以表示得最大的笑臉。而閉圓括號`)`因為給人一種“呵呵”的感覺而不建議使用。
優選:
~~~
:]
~~~
不建議使用:
~~~
:)
~~~
本文版權歸 raywenderlich.com 、[The Official raywenderlich.com Swift Style Guide](https://github.com/raywenderlich/swift-style-guide)項目以及所有貢獻者所有。
譯者翻譯僅供知識傳播使用。
本風格指南的目標是讓Swift代碼更簡潔、可讀更強。