Swift Closure(閉包)

法蘭克的 iOS 世界
5 min readFeb 27, 2017

--

Closure(閉包)是什麼呢?它就像是一個沒有名稱的函數,也被稱做 匿名函數。它,無所不在,不管是在底層或第三方的框架中,這代表 Closure 在 Swift 裡是學習重點之一。若在學習初期若還不是對閉包那麼的熟悉,可以把它想像成就只是個方法,可被宣告成 property 或 parameter。列舉兩個在開發時常見的情境:

  1. 當需要呼叫 API 時,通常會透過一個函數去呼叫它,在這個函數裡總是會使用非同步的方式去呼叫 API,此時就得等待非同步的任務完成時,Callback 回來接著再執行繼續下一個任務。
  2. 在高階函數裡,總是也會因為要判斷某個值的結果而大量使用。
  3. closure 被宣告成 property,用來當物件和物件之間的溝通的橋樑。

簡而言之,閉包就是個可被呼叫的函數而已,只是長得較奇怪。而 Swift 中的閉包和 Objective-C 的 blocks 都有異曲同工之妙,而它們的概念也是大同小異的。以下將開始說明什麼是閉包、閉包的應用、使用的時機點等等😀

宣告方式

{ (參數) -> 回傳型別 in    處理邏輯...}

宣告閉包並將其存放在變數中,最後呼叫它

宣告閉包的 Property

將函式存放在變數中並呼叫它

函數也可以被當成參數來傳遞

說穿了 Closure 就是一個 Block,其可以是自行宣告的,也可以是 func 的;也可 Capture 值,也可有回傳值。

範例1:

撰寫一個函式,第一個參數為字串,第二個參數為閉包函式。

呼叫此閉包函式,會得到 “Hello Frank” 的結果。

範例2:

以下開始介紹閉包從最完整到最簡潔的寫法,首先撰寫一個加法功能的閉包函式,並使用最原始的方式來呼叫它,最後會得到結果 15。

根據上下文推測型別(Inferring Type From Context)

通過內聯閉包運算式所構造的閉包作為參數傳遞給函數時,都可以推測出閉包的參數和返回值的型別,所以就可以拿掉「小括號」和「參數型別」。

閉包單行表示式隱含返回(Implicit Return From Single-Expression Closure)

單行運算式閉包可以通過隱藏 return 關鍵字來隱含返回單行運算式的結果。

參數名稱縮寫(Shorthand Argument Names)

在閉包運算式中可以使用參數名稱縮寫,例如第一個參數可以寫成 $0,第二個參數則可以寫成 $1,然而這樣的寫法就也可以一併省略 in 關鍵字。

尾隨閉包(Trailing Closure)

若是閉包函式的閉包參數是在最後一個,可使用尾隨閉包(trailing closure syntax)又稱為語法蜜糖(syntax sugar)來處理,把閉包參數放在最後的大括號即可。

範例3:

開發常用到的 UIViewController present(_:animated:completion:)

let next: NextUIViewController = NextUIViewController()self.present(next, animated: true, completion: {() -> Void in print(“to next…”)})

Apple Documentation 所示

當我們呼叫 present(_:animated:completion:) 時,會先執行切換頁數、處理動畫等邏輯,最後再呼叫閉包函式,也就是印出「to next…」的區塊。

範例4:

撰寫類高階函數的 filter 的閉包函式。

使用時機

到底是否要設計帶有 Closure 的 Function 呢?可以站在被呼叫的 Function 需不需要執行 Callback 的動作 來思考這件事

條件若成立,就考慮設計 closure 來處理該邏輯,再來要考慮的項目:

  1. 是否需要將參數值傳遞給 caller(呼叫者),讓 caller 透過 capture 捕獲得其值?

2. 是否需要取得 caller(呼叫者)的 return 值?

以上條件若是都成立,就得設計一閉包「且」需要將參數值傳遞給 Caller「且」需要取得 Caller 的 Return 值。舉一個 Higher-Order-Fucntions 裡的 filter(_:)來說明,此 Function 的主要用途是可用來過濾出自定義的條件值,這句話已成立以上三個條件,讓我們來看看 Apple 如何定義這個 Function 的 Closure 吧。

filter(_:)

#3

將過濾出的元素集合回傳。

#2

取得 Caller(呼叫者)的 Return 值。

#1

將參數值傳遞給 Caller(呼叫者),讓 Caller 透過 Capture(捕捉)的方式捕獲得其值

使用方式如下:

以上,若還是不太懂,可以回頭看看範例 4,相信會更清楚明白些😀

如果您喜歡我的文章,請多按幾下「拍手」給我鼓勵,或是按「follow」讓我持續提供好文章給您。

--

--