Swift: 語法秘笈
作者:Andyy Hope, 原文鏈接 ,原文日期:2016/07/20
↑ ↑ ↓ ↓ ← → ← → B A
無論 Swift 是你的第一門開發語言,還是從 Objective-C 轉來,Swift 這門強大的語言都值得我們去學習和使用,但是 Swift 語法的不斷迭代更新可能會令你畏懼。本文將會列舉一些常見的語法,來幫助你提高 Swift 語言能力,精煉代碼。
閉包(Closure)
() -> Void
有些文章中也會稱作 匿名函數 (unnamed functions),類似于 C 或 Objective-C 中的 block ;閉包是一個很輕量但是功能十分強大的函數,常用于類間的值傳遞,閉包通常作為函數的參數來使用,當然也可以作為變量。
如果你有過 iOS 開發經驗,你在使用 UIView animation 的 API 時肯定會用到閉包:
class func animateWithDuration(_ duration: NSTimeInterval, animations: () -> Void)
animation 參數:傳入動畫相關代碼,例如:
UIView.animateWithDuration(10.0, animations: {
button.alpha = 0
})
animationWithDuration 這個函數利用了閉包,最終我們看到的效果是 button 逐漸消失,直到 alpha 屬性為 0 (不可見狀態)。
尾部閉包(Trailing closures)
UIView.animateWithDuration(10.0) {
button.alpha = 0
}
Swift 的這個特點可以省去很多無用代碼。我們再看上面的代碼,仔細的同學已經發現在相同的 API 我們上面的寫法節省了很多代碼。
因為在 animateWithDuration 方法中最后一個參數是閉包,顧名思義,稱之為 尾部閉包 。尾部閉包允許我們省略參數名,并且能放置在參數表括號以外,進一步簡潔代碼。以下兩個代碼實現功能相同,但是后者使用了尾部閉包:
func say(message: String, completion: () -> Void) {
print(message)
completion()
}
...
say("Hello", completion: {
// prints: "Hello"
// Do some other stuff
})
say("Hello") {
// prints: "Hello"
// Do some other stuff
}
類型別名(Type Alias)
typealias
當我們大量的使用某一種類型來定義時,類型別名是一種方便的手段。比如說我們有一個函數,它的參數是閉包:
func dance(do: (Int, String, Double) -> (Int, String, Double)) { }
這看上去并不復雜,但是如果我們想在多個函數間相互傳遞這個閉包呢?我們不得不記住他的參數名,以確保它在函數中可傳遞。如果參數名不相同,就無法編譯成功,錯誤日志會提示在這個傳遞過程中保證參數名相同。
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)) { }
倘若我們交換參數順序、改變返回值類型,同樣的會出現上述問題。所以,一旦我們更改需求,我們需要更新所有出現這個閉包的地方,這種問題的處理方法將會十分繁瑣。所以,我們引入 類型別名 來解決這個問題。
typealias TripleThreat = (Int, String, Double) -> (Int, String, Double)
...
func dance(dance: TripleThreat) { }
func act(act: TripleThreat) { }
func sing(sing: TripleThreat) { }
現在我們重寫之前的所有方法。如果再想更改參數閉包的話,我們所要做的僅僅是修改 typealias 即可。
類型別名代表性的用法(Famous Type Aliases)
typealias Void = ()
typealias NSTimeInterval = Double
參數名縮寫(Shorthand argument names)
$0, $1, $2...
如果一個閉包中有一個或多個參數,Swift 允許我們通過參數名來訪問參數:
func say(message: String, completion: (goodbye: String) -> Void) {
print(message)
completion(goodbye: "Goodbye")
}
...
say("Hi") { (goodbye: String) -> Void in
print(goodbye)
}
// prints: "Hi"
// prints: "Goodbye"
這個例子中,我們的尾部閉包中有一個名為 goodbye 的 String 型參數,Xcode 會將這個參數放到一個元祖中,然后緊跟著一個類型代表返回值,最后再加上 in 關鍵字來代表參數的結束。下一行則是我們閉包的具體實現。當我們的閉包短小,具有高可讀性時,我們可以追求更加簡潔的寫法。我們現在開始減少代碼,以達到極小:
(goodbye: String) -> Void in
很多代碼都不是必要的,因為我們可以使用 參數名縮寫 。
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
Return Self
-> Self
Swift 2.0 發布的時候,帶來了一系列的新特性例如 map 、 flatMap 等等。更有趣的是,在這些方法中,我們同樣的可以使用 $ 符號來通過序號對其操作:
[1, 2, 3, nil, 5]
.flatMap { $0 } // remove nils
.filter { $0 < 3 } // filter numbers that are greater than 2
.map { $0 * 100 } // multiply each value by 100
// [100, 200]
很酷吧?這種寫法比較優雅、可讀,易于理解。我們應該在更多的地方使用它。
另外,我們可以通過閉包創建一個 String 的擴展,我們對 String 上執行一堆操作,并返回自己而不是使函數返回無效:
// extension UIView
func withBackgroundColor(color: UIColor) -> Self {
backgroundColor = color
return self
}
func withCornerRadius(radius: CGFloat) -> Self {
layer.cornerRadius = 3
return self
}
...
let view = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
.withBackgroundColor(.blackColor())
.withCornerRadius(3)
總結
無論你是在寫新的功能還是在讀舊的代碼,你會發現這種精煉代碼的方式在任何地方都適用,并且你已經掌握了精煉方法。由于 Xcode 的自動補全現在還不完善,所以你應該不斷地去質疑自己的代碼,不要過度的依賴自動補全,而是自主完成代碼。
另外,我在 github 上提供了一個playground文件以方便你來測試以上內容。
譯者注:譯者自己整理了原作者的示例代碼,并加上中文注釋,詳見譯者的 Github倉庫
如果你喜歡這篇文章,并且對你的Coding Style有所幫助,可以在 推ter 聯系并follow我。
我將會在九月與一群swift愛好者參與 try! Swift NYC ,到時候我們不見不散。
本文由 SwiftGG 翻譯組翻譯,已經獲得作者翻譯授權,最新文章請訪問http://swift.gg。
來自:http://swift.gg/2016/08/17/developing-tvos-apps-for-apple-tv-with-swift/