Swift style guide

Swift style guide.

Introduction

API Design Guidelines是蘋果專門針對(duì)API的一個(gè)規(guī)范渐北,本規(guī)范涉及到一些相關(guān)的內(nèi)容牛欢,大都是保持和蘋果的規(guī)范一致。

它絕大部分內(nèi)容惹恃,集合了The Official raywenderlich.com Swift Style Guide.GitHub's Swift Style Guide夭谤,并刪減了一些不適合編碼的規(guī)則。

同時(shí)巫糙,Swift語(yǔ)言在快速的發(fā)展中朗儒,這個(gè)規(guī)范也會(huì)隨著Swift的發(fā)展、以及對(duì)Swift更多的使用和了解参淹,持續(xù)地進(jìn)行修改和完善醉锄。

Table of Contents

<h2 id="correctness"> Correctness </h2>

在Swift中把warnings當(dāng)做errors。該規(guī)則會(huì)解決掉很多其他的代碼格式化規(guī)則浙值,比如不要使用 ++--操作符恳不、不要使用C類型的for循環(huán)、不要直接使用字符串作為selector等开呐。

<h2 id="naming"> Naming </h2>

classes, structures, enumerations 和 protocols采用首字母寫的駝峰命名法烟勋,method names and variables采用首字母寫的駝峰命名法规求。

Preferred:

swift
private let maximumWidgetCount = 100

class WidgetContainer {
  var widgetButton: UIButton
  let widgetHeightPercentage = 0.85
}

Not Preferred:

swift
let MAX_WIDGET_COUNT = 100

class app_widgetContainer {
  var wBut: UIButton
  let wHeightPct = 0.85
}

縮寫應(yīng)該避免,但如URL卵惦、ID這種常見(jiàn)的縮寫可以使用阻肿。

API Design Guidelines中提到,如果使用這些縮寫沮尿,字母應(yīng)該全為大寫或者小寫丛塌。Examples:

Preferred

let urlString: URLString
let userID: UserID

Not Preferred

let uRLString: UrlString
let userId: UserId

使用argument label,替代注釋畜疾,使代碼self-documenting赴邻,可讀性更強(qiáng)。

swift
func convertPointAt(column: Int, row: Int) -> CGPoint
func timedAction(afterDelay delay: NSTimeInterval, perform action: SKAction) -> SKAction!

// would be called like this:
convertPointAt(column: 42, row: 13)
timedAction(afterDelay: 1.0, perform: someOtherAction)

<h3 id="protocols"> Protocols </h3>

按照蘋果的API Design Guidelines啡捶,Protocols名字可以使用名詞來(lái)描述這個(gè)Protocol的內(nèi)容乍楚,比如Collection, WidgetFactory

或以-ing届慈、-able結(jié)尾來(lái)描述Protocol實(shí)現(xiàn)的一些功能,比如: Equatable, Resizing忿偷。

<h3 id="enumerations"> Enumerations </h3>

按照蘋果的API Design Guidelines金顿,枚舉值使用小寫開(kāi)頭的駝峰命名法,也就是lowerCamelCase鲤桥。

swift
enum Shape {
  case rectangle
  case square
  case rightTriangle
  case equilateralTriangle
}

<h3 id="class-prefixes"> Class Prefixes </h3>

在Swift里面揍拆,每一個(gè)module都是一個(gè)namesapce。而在ObjC里沒(méi)有namespace的概念茶凳,只是在每個(gè)類名前面添加前綴嫂拴,比如NSArray。

當(dāng)不同的module有同名的類名時(shí)贮喧,需要指明module name筒狠。

swift
import SomeModule

let myClass = MyModule.UsefulClass()

<h3 id="selectors"> Selectors </h3>

Selectors是在ObjC中為許多Cocoa and Cocoa Touch APIs做處理的函數(shù)。在Swift2.2箱沦,我們可以使用類型不安全的字符串來(lái)指定一個(gè)Selector辩恼。但在Swift3,這種方式將使Xcode報(bào)一個(gè)警告,在警告的"Fix it"按鈕里面谓形,會(huì)使用完全類型安全的方式去替換這個(gè)不安全的字符串灶伊。并且我們經(jīng)常能夠使用代碼所在的上下文來(lái)簡(jiǎn)化Swift3中Selector的表達(dá)式。

Preferred:

swift
let sel = #selector(viewDidLoad)

Not Preferred:


swift
let sel = #selector(ViewController.viewDidLoad)

<h3 id="generics"> Generics </h3>

范型的類型名寒跳,應(yīng)該是描述性的名詞聘萨、以大寫開(kāi)頭的駝峰命名。如果不能起一個(gè)有意義的關(guān)系或角色名稱童太,可以使用T米辐、UV胸完。

Preferred:

swift
struct Stack<Element> { ... }
func writeTo<Target: OutputStream>(inout target: Target)
func max<T: Comparable>(x: T, _ y: T) -> T

Not Preferred:

swift
struct Stack<T> { ... }
func writeTo<target: OutputStream>(inout t: target)
func max<Thing: Comparable>(x: Thing, _ y: Thing) -> Thing

<h3 id="language"> Language </h3>

為了和蘋果的API匹配,使用美式英語(yǔ)儡循。

Preferred:

swift
let color = "red"

Not Preferred:

swift
let colour = "red"

<h2 id="code-organization"> Code Organization </h2>

多使用extension來(lái)組織代碼舶吗。每個(gè) extensions使用// MARK: -來(lái)分隔開(kāi)。

<h3 id="protocol-conformance"> Protocol Conformance </h3>

當(dāng)一個(gè)類遵守一個(gè)協(xié)議時(shí)择膝,使用extension來(lái)組織代碼誓琼。

Preferred:

swift
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
}

Not Preferred:

swift
class MyViewcontroller: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
  // all methods
}

<h3 id="unused-code"> Unused Code </h3>

能刪除的代碼,都刪掉肴捉。

Not Preferred:

swift
override func didReceiveMemoryWarning() {
   super.didReceiveMemoryWarning()
  // Dispose of any resources that can be recreated.
}

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
   // #warning Incomplete implementation, return the number of sections
   return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  // #warning Incomplete implementation, return the number of rows
  return Database.contacts.count
}

Preferred:

swift
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  return Database.contacts.count
}

<h3 id="minimal-imports"> Minimal Imports </h3>

盡可能減少依賴和import腹侣。比如只需要引入Foundation的時(shí)候,就不要引入U(xiǎn)IKit齿穗。

<h2 id="spacing"> Spacing </h2>

  • 縮進(jìn)使用4個(gè)空格(該處只要團(tuán)隊(duì)統(tǒng)一就行):
  • 方法體的花括號(hào)和其它的花括號(hào)(if/else/switch/while etc.)傲隶,需要加入一個(gè)空格后在行尾開(kāi)啟,在新一行關(guān)閉(Xcode默認(rèn))窃页。
  • 提示:?A選中代碼后使用Control-I (或者菜單Editor\Structure\Re-Indent)來(lái)調(diào)整縮進(jìn).

Preferred:

swift
if user.isHappy {
  // Do something
} else {
  // Do something else
}

Not Preferred:

swift
if user.isHappy
{
  // Do something
}
else {
  // Do something else
}
  • methods之間只留一個(gè)空行跺株。methods內(nèi)部,使用空行來(lái)分隔不同功能的代碼脖卖,為不同的section乒省。一個(gè)method內(nèi)部的section不宜太多,否則應(yīng)該考慮分拆成不同函數(shù)畦木。
  • 冒號(hào)左邊沒(méi)有空格袖扛,右邊有一個(gè)空格。Exception:? :[:]十籍。

Preferred:

swift
class TestDatabase: Database {
  var data: [String: CGFloat] = ["A": 1.2, "B": 3.2]
}

Not Preferred:

swift
class TestDatabase : Database {
  var data :[String:CGFloat] = ["A" : 1.2, "B":3.2]
}

<h2 id="comments"> Comments </h2>

盡可能避免大量使用注釋蛆封,好的代碼應(yīng)該盡可能是self-documenting。

如果需要注釋勾栗,它只用來(lái)解釋為什么這段代碼要這么寫惨篱,而不是解釋代碼的邏輯。
代碼變化時(shí)也需要馬上更新注釋械姻,不能有誤導(dǎo)妒蛇。如果不能及時(shí)更新就刪掉該處注釋。

Exception: 上面兩條不適用于生成文檔用的注釋.

<h2 id="classes-and-structures"> Classes and Structures </h2>

應(yīng)該使用哪一個(gè)?

記住楷拳,struct具有值語(yǔ)義绣夺。沒(méi)有id(唯一標(biāo)識(shí)符)的事物就應(yīng)該使用struct。比如一個(gè)含有[a, b, c]的數(shù)組和另一個(gè)含有[a, b, c]的數(shù)組是完全可交換的欢揖。你使用第一個(gè)數(shù)組還是第二個(gè)完全沒(méi)有關(guān)系陶耍,因?yàn)樗麄兇硗粋€(gè)事物,這也是為什么在Swift里面數(shù)組是用struct結(jié)構(gòu)來(lái)表示的她混。

而類具有引用語(yǔ)義烈钞。具有id(唯一標(biāo)識(shí)符)或者具有特定生命周期的事物就應(yīng)該使用類來(lái)表示泊碑。你將使用類來(lái)表示人的數(shù)據(jù)結(jié)構(gòu),因?yàn)閮蓚€(gè)人完全是不同的事物毯欣,只是因?yàn)閮蓚€(gè)人具有相同名字和生日馒过,并不意味著這是相同的一個(gè)人。但是一個(gè)人的生日可以使用struct來(lái)表示酗钞,因?yàn)橐粋€(gè)變量中的1950年3月3號(hào)和另一個(gè)的1950年3月3號(hào)是完全相同的腹忽。日期是不具有id的。

但有些時(shí)候砚作,一個(gè)事物應(yīng)該是struct的窘奏,但需要遵循AnyObject或者由于歷史原因被模型化為類了(NSDate, NSSet)。除了這些異常情況葫录,盡量遵循該條原則着裹。

<h3 id="example-definition"> Example definition </h3>

下面是一個(gè)比較規(guī)范的Class定義:

swift
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))"
  }
}

上面的例子,給我們演示了這些規(guī)范:

  • 冒號(hào)在用于指明類型時(shí)米同,左邊沒(méi)有空格骇扇,右邊有一個(gè)空格。
  • 當(dāng)一組變量面粮、常量有關(guān)聯(lián)時(shí)匠题,定義在一行里。
  • 函數(shù)修飾符internal是缺省值但金,可以省略。重載一個(gè)函數(shù)時(shí)郁季,訪問(wèn)修飾符也可以省略掉冷溃。

<h3 id="use-of-self"> Use of Self </h3>

避免使用self來(lái)訪問(wèn)屬性。除非需要區(qū)分函數(shù)參數(shù)和屬性梦裂。

swift
class BoardLocation {
  let row: Int, column: Int

  init(row: Int, column: Int) {
    self.row = row
    self.column = column
    
    let closure = {
      print(self.row)
    }
  }
}

<h3 id="computed-properties"> Computed Properties </h3>

Computed property一般是只讀似枕,同時(shí)省略get clause。get clause只是當(dāng)set clause存在時(shí)才需要寫年柠。

Preferred:

swift
var diameter: Double {
  return radius * 2
}

Not Preferred:

swift
var diameter: Double {
  get {
    return radius * 2
  }
}

<h3 id="final"> Final </h3>

當(dāng)一個(gè)類不想被繼承時(shí)凿歼,使用final關(guān)鍵字。Example:

swift
// Turn any generic type into a reference type using this Box class.
final class Box<T> {
  let value: T 
  init(_ value: T) {
    self.value = value
  }
}

<h2 id="function-declarations"> Function Declarations </h2>

在一行中保持簡(jiǎn)短的函數(shù)聲明冗恨,函數(shù)體的左方括號(hào)也需要放在這一行答憔。

swift
func reticulateSplines(spline: [Double]) -> Bool {
  // reticulate code goes here
}

如果一個(gè)函數(shù)簽名過(guò)長(zhǎng),則選擇合適的地方換行掀抹,并在新的一行加入足夠的縮進(jìn)虐拓。

swift
func reticulateSplines(spline: [Double], adjustmentFactor: Double,
    translateConstant: Int, comment: String) -> Bool {
  // reticulate code goes here
}

<h2 id="closure-expressions"> Closure Expressions </h2>

方法的參數(shù)列表最后一參數(shù)類型為閉包時(shí),可以使用尾閉包傲武。但只在只存在一個(gè)閉包參數(shù)時(shí)才使用尾閉包蓉驹。

Preferred:

swift
UIView.animateWithDuration(1.0) {
  self.myView.alpha = 0
}

UIView.animateWithDuration(1.0,
  animations: {
    self.myView.alpha = 0
  },
  completion: { finished in
    self.myView.removeFromSuperview()
  }
)

Not Preferred:

swift
UIView.animateWithDuration(1.0, animations: {
  self.myView.alpha = 0
})

UIView.animateWithDuration(1.0,
  animations: {
    self.myView.alpha = 0
  }) { f in
    self.myView.removeFromSuperview()
}

只有一個(gè)表達(dá)式的城榛、用來(lái)返回值的閉包,可以省略return态兴。

swift
attendeeList.sort { a, b in
  a > b
}

<h2 id="types"> Types </h2>

盡可能使用Swift原生類型狠持,而不是使用ObjC的NS類型。

Preferred:

swift
let width = 120.0                                    // Double
let widthString = (width as NSNumber).stringValue    // String

Not Preferred:

swift
let width: NSNumber = 120.0                          // NSNumber
let widthString: NSString = width.stringValue        // NSString

但是有些情況例外瞻润,比如在寫Sprite Kit代碼時(shí)喘垂,用CGFloat可以減少轉(zhuǎn)換。

<h3 id="constants"> constants </h3>

盡可能使用let敢订,只有在需要使用變量的時(shí)候使用var王污。

Tip: 有一個(gè)辦法能達(dá)到上面的目的,就是自己只寫let楚午,讓編譯器幫你確定哪些需要改成var昭齐。

使用static let定義類常量,而不是實(shí)例常量矾柜,或者全局常量阱驾。

Preferred:

swift
enum Math {
  static let e  = 2.718281828459045235360287
  static let pi = 3.141592653589793238462643
}

radius * Math.pi * 2 // circumference

Note: 使用枚舉定義常量的好處是讓常量定義在特定的命名空間。

Not Preferred:

swift
let e  = 2.718281828459045235360287  // pollutes global namespace
let pi = 3.141592653589793238462643

radius * pi * 2 // is pi instance data or a global constant?

<h3 id="optionals"> Optionals </h3>

當(dāng)訪問(wèn)一個(gè)optional value前怪蔑,需要訪問(wèn)多個(gè)optional value時(shí)里覆,使用optional chaining:

swift
self.textContainer?.textLabel?.setNeedsDisplay()

訪問(wèn)一個(gè)optional value后,需要執(zhí)行多個(gè)操作缆瓣,可以使用optional binding:

swift
if let textContainer = self.textContainer {
  // do many things with textContainer
}

給optional變量命名時(shí)喧枷,不要使用類似optionalStringmaybeView這樣的命名,因?yàn)閛ptional已經(jīng)在類型聲明中體現(xiàn)弓坞。

相對(duì)應(yīng)的隧甚,使用unwrapped value時(shí),避免使用unwrappedViewactualLabel這樣的命名渡冻,使用optional變量名就可以了戚扳。

Preferred:

swift
var subview: UIView?
var volume: Double?

// later on...
if let subview = subview, volume = volume {
  // do something with unwrapped subview and volume
}

Not Preferred:

swift
var optionalSubview: UIView?
var volume: Double?

if let unwrappedSubview = optionalSubview {
  if let realVolume = volume {
    // do something with unwrappedSubview and realVolume
  }
}

避免使用可選值的強(qiáng)制解析

如果你有一個(gè)變量 fooFooType? 或者 FooType!類型,如果可能族吻,盡量不要使用強(qiáng)制解析來(lái)獲取 foo真正的值帽借。

Preferred:

swift
if let foo = foo {
    // Use unwrapped `foo` value in here
} else {
    // If appropriate, handle the case where the optional is nil
}

或者,在一些情況下你可以使用可選鏈超歌,例如:

swift
// Call the function if `foo` is not nil. If `foo` is nil, ignore we ever tried to make the call
foo?.callSomethingIfFooIsNotNil()

顯示的 if let可選綁定是安全的代碼范式砍艾。強(qiáng)制解析常常會(huì)引起運(yùn)行時(shí)的崩潰。

避免使用隱士強(qiáng)制解析

如果 foo可以是nil, 盡量使用 let foo: FooType?這種范式巍举,而不要使用let foo: FooType! (一般來(lái)說(shuō)辐董,使用!的地方都可以使用?)

顯示的可選類型是安全的代碼范式。隱士強(qiáng)制解析有可能引起運(yùn)行時(shí)的崩潰禀综。

<h3 id="struct-initializers"> Struct Initializers </h3>

使用Swfit原生的struct initializers简烘,而不是遺留的CGGeometry constructors苔严。

Preferred:

swift
let bounds = CGRect(x: 40, y: 20, width: 120, height: 80)
let centerPoint = CGPoint(x: 96, y: 42)

Not Preferred:

swift
let bounds = CGRectMake(40, 20, 120, 80)
let centerPoint = CGPointMake(96, 42)

同樣的,使用struct-scope constants CGRect.infinite孤澎, CGRect.null届氢, etc, 而不是global constants CGRectInfinite, CGRectNull, etc覆旭。
你也可以使用.zero來(lái)給變量賦值退子,如var frame = CGRect.zero。對(duì)于一個(gè)已經(jīng)存在的變量也可以這樣bounds = .zero

<h3 id="lazy-initialization"> Lazy Initialization </h3>

合適的時(shí)候考慮使用lazy加載來(lái)更好的控制一個(gè)對(duì)象的生命周期型将。這對(duì)UIViewController懶加載view特別有用寂祥。你可以使用一個(gè)形如 { }() 的立即調(diào)用的閉包,或者調(diào)用一個(gè)private的工廠函數(shù)七兜。例如:

swift
lazy var locationManager: CLLocationManager = self.makeLocationManager()

private func makeLocationManager() -> CLLocationManager {
  let manager = CLLocationManager()
  manager.desiredAccuracy = kCLLocationAccuracyBest
  manager.delegate = self
  manager.requestAlwaysAuthorization()
  return manager
}

Notes:

  • [unowned self] 在這里不需要丸凭,這里不會(huì)產(chǎn)生循環(huán)引用。
  • 因?yàn)長(zhǎng)ocation manager會(huì)彈出彈框詢問(wèn)用戶定位的權(quán)限腕铸,所以這里控制它的生命周期很有意義惜犀。

<h3 id="type-inference"> Type Inference </h3>

盡量讓編譯器使用類型推斷來(lái)標(biāo)示常量或者變量的類型,這樣可以簡(jiǎn)短代碼狠裹。類型推斷也適用于小數(shù)據(jù)量(不為空)的數(shù)組和字典虽界。只有當(dāng)需要的時(shí)候,才指明類型涛菠,如CGFloat or Int16莉御。

Preferred:

swift
let message = "Click the button"
let currentBounds = computeViewBounds()
var names = ["Mic", "Sam", "Christine"]
let maximumWidth: CGFloat = 106.5

Not Preferred:

swift
let message: String = "Click the button"
let currentBounds: CGRect = computeViewBounds()
let names = [String]()

空數(shù)組或者字典的類型標(biāo)注

對(duì)于空的數(shù)組、字典需要顯示使用類型標(biāo)注俗冻。對(duì)于初始化的時(shí)候使用大量颈将、對(duì)方數(shù)組、字典常量初始化的情況也需要顯示使用類型標(biāo)注言疗。

Preferred:

swift
var names: [String] = []
var lookup: [String: Int] = [:]

Not Preferred:

swift
var names = [String]()
var lookup = [String: Int]()

NOTE: 準(zhǔn)守這條規(guī)則意味著取一個(gè)描述性的名稱顯示更加重要。

<h3 id="syntactic-sugar"> Syntactic Sugar </h3>

盡可能使用語(yǔ)法糖颂砸。

Preferred:

swift
var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?

Not Preferred:

swift
var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>

<h2 id="functions-vs-methods"> Functions vs Methods </h2>

不依附于任何class或type的函數(shù)被稱為free function噪奄,應(yīng)該盡量避免使用虾啦,因?yàn)椴惶谜业竭@個(gè)方法朝捆。

Preferred

swift
let sorted = items.mergeSort()  // easily discoverable
rocket.launch()  // clearly acts on the model

Not Preferred

swift
let sorted = mergeSort(items)  // hard to discover
launch(&rocket)

Free Function Exceptions(下面的函數(shù)明確應(yīng)該是fress function,并且比較好理解)

swift
let tuples = zip(a, b)  // feels natural as a free function (symmetry)
let value = max(x,y,z)  // another free function that feels natural

<h2 id="memory-management"> Memory Management </h2>

代碼應(yīng)該避免參數(shù)循環(huán)引用拨扶。分析你的對(duì)象引用視圖纹因,并使用weakunowned避免不必要的強(qiáng)引用齐帚。同時(shí)可以選擇使用值類型(struct, enum)來(lái)避免循環(huán)引用追葡。

擴(kuò)展一個(gè)對(duì)象的生命周期

可以使用 [weak self]guard let strongSelf = self else { return } 組合的方式來(lái)擴(kuò)展一個(gè)對(duì)象的生命周期喇颁。當(dāng) self 明顯生命周期比使用它的閉包更長(zhǎng)的時(shí)候阱缓,最好選擇使用 [unowned self]戳护。

Preferred

swift
resource.request().onComplete { [weak self] response in
  guard let strongSelf = self else { 
    return 
  }
  let model = strongSelf.updateModel(response)
  strongSelf.updateUI(model)
}

Not Preferred

swift
// might crash if self is released before response returns
resource.request().onComplete { [unowned self] response in
  let model = self.updateModel(response)
  self.updateUI(model)
}

Not Preferred

swift
// deallocate could happen between updating the model and updating UI
resource.request().onComplete { [weak self] response in
  let model = self?.updateModel(response)
  self?.updateUI(model)
}

<h2 id="access-control"> Access Control </h2>

訪問(wèn)修飾符應(yīng)該放在靠前的位置金抡,前面只能有static瀑焦、@IBAction@IBOutlet

Preferred:

swift
class TimeMachine {  
  private dynamic lazy var fluxCapacitor = FluxCapacitor()
}

Not Preferred:

swift
class TimeMachine {  
  lazy dynamic private var fluxCapacitor = FluxCapacitor()
}

對(duì)于全局的定義梗肝,一點(diǎn)顯示的標(biāo)示訪問(wèn)修飾符

頂層的函數(shù)榛瓮、類型、變量總是應(yīng)該顯示的指明訪問(wèn)修飾符:

swift
public var whoopsGlobalState: Int
internal struct TheFez {}
private func doTheThings(things: [Thing]) {}

但是對(duì)于不少頂層的聲明巫击,如果可以盡量不要顯示指定訪問(wèn)修飾符:

swift
internal struct TheFez {
    var owner: Person = Joshaber()
}

對(duì)于頂層的(全局的)聲明很少有被指定為 internal 的情況禀晓,顯示的指明訪問(wèn)修飾符可以保證這個(gè)頂層聲明的設(shè)計(jì)是被充分考慮過(guò)的。但在這些聲明里面坝锰,使用已有的訪問(wèn)修飾符是更好的方式粹懒。

<h2 id="control-flow"> Control Flow </h2>

相比于 while-condition-increment 格式的循環(huán),請(qǐng)盡量使用 for-in 這種方式顷级。

Preferred:

swift
for _ in 0..<3 {
  print("Hello three times")
}

for (index, person) in attendeeList.enumerate() {
  print("\(person) is at position #\(index)")
}

for index in 0.stride(to: items.count, by: 2) {
  print(index)
}

for index in (0...3).reverse() {
  print(index)
}

Not Preferred:

swift
var i = 0
while i < 3 {
  print("Hello three times")
  i += 1
}


var i = 0
while i < attendeeList.count {
  let person = attendeeList[i]
  print("\(person) is at position #\(i)")
  i += 1
}

<h2 id="golden-path"> Golden Path </h2>

嵌套的if會(huì)讓代碼的縮進(jìn)層次不齊(整齊的縮進(jìn)被稱作Golden Path)凫乖,會(huì)讓代碼可讀性變差,使用guard來(lái)做函數(shù)輸入合法性檢查愕把,可以減少if嵌套拣凹。

Preferred:

swift
func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {

  guard let context = context else { 
    throw FFTError.noContext 
  }
  guard let inputData = inputData else { 
    throw FFTError.noInputData 
  }
    
  // use context and input to compute the frequencies
    
  return frequencies
}

Not Preferred:

swift
func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {

  if let context = context {
    if let inputData = inputData {
      // use context and input to compute the frequencies

      return frequencies
    }
    else {
      throw FFTError.noInputData
    }
  }
  else {
    throw FFTError.noContext
  }
}

Preferred:

swift
guard let number1 = number1, 
        number2 = number2, 
        number3 = number3 else { 
        fatalError("impossible") 
}
// do something with numbers

Not Preferred:

swift
if let number1 = number1 {
  if let number2 = number2 {
    if let number3 = number3 {
      // do something with numbers
    }
    else {
      fatalError("impossible")
    }
  }
  else {
    fatalError("impossible")
  }
}
else {
  fatalError("impossible")
}

<h3 id="failing-guards"> Failing Guards </h3>

Guard檢查失敗執(zhí)行的語(yǔ)句應(yīng)該退出當(dāng)前方法,并且應(yīng)該只有一條語(yǔ)句恨豁,如return, throw, break, continue, and fatalError()嚣镜。如果需要多行語(yǔ)句,考慮使用defer橘蜜。

<h2 id="semicolons"> Semicolons </h2>

Swift并不要求每行語(yǔ)句都必須以冒號(hào)結(jié)束菊匿,除了你需要在一行寫多個(gè)語(yǔ)句的情況下。

建議不要在一行寫多個(gè)語(yǔ)句计福。

這條規(guī)則的唯一例外是for-conditional-increment語(yǔ)句跌捆。但是我們推薦使用for-in來(lái)代替?zhèn)鹘y(tǒng)的for語(yǔ)句。

Preferred:

swift
let swift = "not a scripting language"

Not Preferred:

swift
let swift = "not a scripting language";

NOTE: Swift不像JavaScript那樣認(rèn)為省略掉句尾的冒號(hào)是不安全的

<h2 id="parentheses"> Parentheses </h2>

包住條件語(yǔ)句的圓括號(hào)應(yīng)該省略象颖。

Preferred:

swift
if name == "Hello" {
  print("World")
}

Not Preferred:

swift
if (name == "Hello") {
  print("World")
}

<h2 id="use-whitespace-around-operator-definitions"> Use whitespace around operator definitions </h2>

在自定義操作符的時(shí)候佩厚,使用空格作為分割符:

Preferred:

swift
func <| (lhs: Int, rhs: Int) -> Int
func <|< <A>(lhs: A, rhs: A) -> A

Not Preferred:

swift
func <|(lhs: Int, rhs: Int) -> Int
func <|<<A>(lhs: A, rhs: A) -> A

如果構(gòu)成操作符的字符后面立即跟隨類型或者參數(shù)的字符,將使其可讀性變差说订。加入合適的空格將讓它看起來(lái)更加清晰抄瓦。

<h2 id="和xcode集成的格式檢查工具"> 和Xcode集成的格式檢查工具 </h2>
SwiftLint是開(kāi)源社區(qū)貢獻(xiàn)的一個(gè)Swift格式檢查工具,可以較好的和Xcode集成陶冷,并提供warning钙姊、errors和修復(fù)提示的工具。它使用的規(guī)則基本遵循GitHub's Swift Style Guide埂伦,是團(tuán)隊(duì)很好的統(tǒng)一格式的一個(gè)輔助工具煞额。

<h2 id="document-revision-history"> Document Revision History </h2>

  • 2016-11-11 Created by xdyang
  • 2016-11-30 修改搜索跳轉(zhuǎn)方式
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子膊毁,更是在濱河造成了極大的恐慌胀莹,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件媚媒,死亡現(xiàn)場(chǎng)離奇詭異嗜逻,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)缭召,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門栈顷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人嵌巷,你說(shuō)我怎么就攤上這事萄凤。” “怎么了搪哪?”我有些...
    開(kāi)封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵靡努,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我晓折,道長(zhǎng)惑朦,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任漓概,我火速辦了婚禮漾月,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘胃珍。我一直安慰自己梁肿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布觅彰。 她就那樣靜靜地躺著吩蔑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪填抬。 梳的紋絲不亂的頭發(fā)上烛芬,一...
    開(kāi)封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天,我揣著相機(jī)與錄音飒责,去河邊找鬼赘娄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛读拆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鸵闪,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼檐晕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起辟灰,我...
    開(kāi)封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤个榕,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后芥喇,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體西采,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年继控,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了械馆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡武通,死狀恐怖霹崎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冶忱,我是刑警寧澤尾菇,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站囚枪,受9級(jí)特大地震影響派诬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜链沼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一默赂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧忆植,春花似錦放可、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至拾氓,卻和暖如春冯挎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咙鞍。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工房官, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人续滋。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓翰守,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親疲酌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蜡峰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容