#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

--

--

KuoJed
彼得潘的 Swift iOS / Flutter App 開發教室

「沒有一件你努力過的事是白費的。」 當你這麼相信,並且實踐,就會成真。