<h6>無論是你學習的第一門語言是 Swift 還是之前學過 Objective-C,在學習 Swift 的過程中,一定會感嘆它真的是一門超贊的語言。但如果你不熟悉它的某些語法,就可能會被某些寫法嚇到。在這里我會介紹一些在寫 Swift 過程中常見語法,希望你們能用 Swift 寫出更簡潔的代碼。
<h1>Closures(閉包)
() -> Void
<h6>Closure 在 C 或 Objective-C 中也被稱為 “unnamed function”(匿名函數) 或者 “block”(代碼塊)。你可以把閉包當成一個值,傳來傳去,當然也可以把它當成函數的參數。
如果你之前有過 iOS 開發(fā)經驗,那么很有可能調用過這個 UIView 的動畫 API:
class func animate(withDuration duration: NSTimeInterval, animations: @escaping () -> Void)
可以在 animations: 參數中傳入執(zhí)行動畫的代碼,
UIView.animate(withDuration: 10.0, animations: {
button.alpha = 0
})
這個animationWithDuration: 函數會使用我們閉包中的代碼,悄悄地做一些神奇的事情,把 button 的透明調整到 0(不可見)
<h1>Trailing closures(尾隨閉包)
UIView.animate(withDuration: 10.0) {
button.alpha = 0
}
<h6>Swift 使用這種方式來減少不必要的語法。如果你仔細看上面的代碼就會發(fā)現,這和之前在 closure 中舉的例子使用的是相同的 API,唯一的區(qū)別是它的語法被簡化了。
因為 animate 函數的最后一個參數是閉包,所以它得名尾隨閉包。尾隨閉包可以省略最后一個參數的名字,并且可以完全把它移出函數參數列表圓括號的外面,這就帶來了更優(yōu)雅和準確的代碼。下面的函數都是相同的,不過后面的使用了尾隨閉包語法
func say(_ message: String, completion: @escaping () -> Void) {
print(message)
completion()
}
...
say("Hello", completion: {
// prints: "Hello"
// Do some other stuff
})
say("Hello") {
// prints: "Hello"
// Do some other stuff
}
<h1>Type Alias(類型別名)
typealias
<h6>Typealias 是一個能讓我們的寫代碼的時候避免一直重復的實用小工具。有這樣一個函數,參數是一個閉包,
func dance(do: (Int, String, Double) -> (Int, String, Double)) { }
<h6>起初這還挺直接容易理解的,但如果把這個閉包傳到其它函數中去呢?我們還要記住這個閉包的簽名,而且在每一個它出現的地方都要確保它的簽名是正確的。如果有的地方寫錯了,編譯器就會報錯。
func dance(do: (Int, String, Double) -> (Int, String, Double)) { }
func sing(do: (Int, String, Double) -> (Int, String, Double)) { }
func act(do: (Int, String, Double) -> (Int, String, Double)) { }
<h6>如果我們修改了這個閉包的簽名,問題就出現了。比如交換了其中參數或者返回值的順序。我們就得把每一個用到的地方都改一下。這個時候 typealias 就會比較有幫助了。
typealias TripleThreat = (Int, String, Double) -> (Int, String, Double)
...
func dance(dance: TripleThreat) { }
func act(act: TripleThreat) { }
func sing(sing: TripleThreat) { }
<h6>這樣就好多了,用 typealias 替代了很多重復的代碼,而且如果想更改閉包定義的話,直接改 typealias 就可以了。
<h4> 比較「有名的」typealias
typealias Void = ()
typealias NSTimeInterval = Double
<h1>簡寫參數名
$0, $1, $2...
<h6>如果一個閉包有一個或多個參數,Swift 允許我們給它們定義變量名,
func say(_ message: String, completion: (_ goodbye: String) -> Void) {
print(message)
completion("Goodbye")
}
...
say("Hi") { (goodbye: String) -> Void in
print(goodbye)
}
// prints: "Hi"
// prints: "Goodbye"
<h6>在這個例子中,尾隨閉包有一個名為 goodbype 類型是 String 的參數,Xcode 會自動把它放在一個元組里,接著是 -> 、返回值、還有 in,我們的代碼在下一行。但是這個閉包很小,寫這么多代碼是沒有必要的。來分析一下,如何才能寫更少的代碼。
(goodbye: String) -> Void in
<h6>上面的其實都沒有什么存在的必要性,因為可以使用簡化的參數名,
say("Hi") { print($0) }
// prints: "Hi"
// prints: "Goodbye"
可以看到,省略了 goodbye: 參數名,Void 返回類型的定義,還有跟在后面的 in。每一個參數依據它們在閉包中定義的順序而命名。因為語法太簡略了,甚至能把所有的代碼放到一行。
如果閉包的參數多于一個,對于每一個后面的參數,增加簡寫參數的數字就可以了。
(goodbye: String, name: String, age: Int) -> Void in
// $0: goodbye
// $1: name
// $2: age
<h1>返回 Self
-> Self
<h6>Swift 2.0 發(fā)布的時候,新增了一些方法,比如 map 和 flatMap,更酷的是,可以通過點語法把這些方法串起來,
[1, 2, 3, nil, 5]
.flatMap { $0 } // 清除 nil
.filter { $0 < 3 } // 選出小于 3 的值
.map { $0 * 100 } // 每個值乘 100
// [100, 200]
是不是很酷!這種語法非常優(yōu)雅,很容易閱讀和理解,我們應該盡可能多地使用它們。
如果存在一個 String 的 extension,在此方法里面我們做了一些對于這個 String 本身的操作,這個時候函數不要返回 Void,而返回 Self,
// extension UIView
func with(backgroundColor: UIColor) -> Self {
backgroundColor = color
return self
}
func with(cornerRadius: CGFloat) -> Self {
layer.cornerRadius = 3
return self
}
...
let view = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
.with(backgroundColor: .black)
.with(cornerRadius: 3)