#8 Closure的使用方法
開始接觸Swift的世界後, 發現對於Closure感到陌生, 想說用一篇文章來記錄一下使用的方法.
function closure 傻傻分不清楚!?
相信很多人和我一開始都有遇到一樣的問題, 到底什麼是closure? 跟以前學過的function有什麼不同?
簡單來說, closure可以看成是沒有名稱的function (也因此無法單獨存在, 需要指派給某個變數), 但因為closure有很多不同的簡化方式, 所以簡化到最後通常讓人看不出他的原貌. 為了讓大家能了解它, 接下來就讓我從最簡單的比較開始:
- 沒有參數也沒有回傳值的function
func selfIntroduction () -> () {
print("This is function!")
}selfIntroduction() // 印出結果為: This is function
- 沒有參數也沒有回傳值的closure
let selfIntroduction = { () -> () in
print("This is closure")
}selfIntroduction() // 印出結果為: This is closure
小技巧: 因為closure沒有名稱, 所以把function的名稱移除, 把參數跟回傳的部分直接移進去{ }裡面, 並利用in和原本function裡面的程式碼隔開.
- 簡化沒有參數也沒有回傳值的closure
let selfIntroduction = {
print("This is closure")
}selfIntroduction() // 印出結果為: This is closure
小技巧: 在沒有參數和回傳值的closure, 可以直接把 ( ) -> ( )和 in直接省略.
接收參數的closure
相信你已經對於closure有初步的認識. 接下來, 我們提升一點難度, 看到的是需要接收參數的closure.
let sayHello = { (name: String) in
print("Hello! \(name)")
}sayHello("Peter") // 印出結果為: Hello! Peter
小技巧: 這邊和function不同的一個地方, 在呼叫sayHello的時候, 並不需要再把參數名稱name寫出來.
有回傳值的closure
接著, 我們修改上一個範例, 改成一個有String參數並回傳String的closure.
let sayHello = { (name: String) -> (String) in
return "Hello! \(name)"
}print(sayHello("Peter")) // 印出結果為: Hello! Peter
當作參數的closure
接下來, 進入重頭戲. 原來closure也可以當作參數來使用!? 為了不讓大家一個頭兩個大, 我們這邊先用最簡單的方式來舉例, 一個用closure當作參數的function.
- 參數為closure的function
let description = {
print("This is closure")
}func demo (action: () -> ()){
print("closure as parameter")
action()
}demo(action: description) // 印出結果為: closure as parameter
// This is closure
- 最後一個參數為closure的function(trailing closure)
當function裡面的最後一個參數為closure時, 可以進行簡化, 我們試著把上一個例子來做簡化, 一樣可以得到一樣的結果.
func demo (action: () -> ()){
print("closure as parameter")
action()
}// 原本
demo(action: {() -> () in
print("This is closure") // 印出結果為: closure as parameter
}) // This is closure// 化簡
demo {
print("This is closure") // 印出結果為: closure as parameter
} // This is closure
小技巧: 因為demo裡面只有唯一一個closure參數, 連( )都可以省略.
接著我們再來練習一題化簡的closure, 來測驗看看是否我們真的有搞懂. 這次demo裡面有兩個參數, 一個Int和一個closure.
func demo (num: Int, action: () -> ()){
for _ in 1...num{
action()
}
}// 原本
demo(num: 2, action: {() -> () in
print("This is closure")
})// 化簡
demo(num: 2) {
print("This is closure")
}
Xcode中的closure與自動完成
一開始會想了解closure的原因是在寫xcode的時候, 常會呼叫內建的function, 通常只要一打出前幾個字, Xcode就會自動跳出提示讓你選擇. 雖然方便, 但有時候顯示出的選項看的不是很懂, 所以才決定先來熟悉一下closure的用法. 下面我們一樣舉個實際例子來做討論. 首先, 我們先定義一個function.
func demo (num: Int = 2, action: () -> () = {}){
for i in 1...num{
print("\(i)")
action()
}
}
這個function有兩個參數. 一個整數 (如果未輸入則預設值為2), 一個closure (如果未輸入則預設為一個空的closure). 功能為執行num次action這個closure, 並在每次執行時印出i的數字.
當今天我們想使用這個function時, 只要輸入demo, 則會跳出這幾個選項:
- 選擇第一個選項 Void demo()
表示使用者不需輸入任何參數, 直接使用預設的參數. 直接執行的結果為:
1
2
- 選擇Void demo (num: Int, action: ( ) -> ( ))
首先我們先輸入num的數字 (假設代入2), 接著按下tab跳到第二個參數, 我們可以直接代入一個closure, 但如果你試過直接按下enter時, 你會發現Xcode直接幫我們化簡:
如果我們今天要代入的closure為print(“trailing closure test”), 下面這兩種寫法都會得到一樣的結果.
1
trailing closure test
2
trailing closure test