天天看點

QiuZH‘s Swift Learn|Swift 閉包

閉包是獨立的功能塊,可以在代碼中傳遞和使用。<code>Swift</code> 中的閉包類似于 <code>C</code> 和 <code>Objective-C</code> 中的 <code>Block</code> 以及其他程式設計語言中的 <code>lambda</code>(匿名函數)。 閉包可以從定義它們的上下文中捕獲和存儲對任何常量和變量的引用。這稱為關閉這些常量和變量。<code>Swift</code> 為您處理所有捕獲的記憶體管理。

以上是Swift 官方對閉包的概述。閉包是引用類型,與函數一樣。無論何時将函數或閉包指派給常量或變量,實際上都是将該常量或變量設定為對函數或閉包的引用。

在Functions 中介紹的全局和嵌套函數實際上是閉包的特殊情況。閉包采用以下三種形式之一:

全局函數是具有名稱且不捕獲任何值的閉包。

嵌套函數是具有名稱并且可以從其封閉函數中捕獲值的閉包。

閉包表達式是用輕量級文法編寫的未命名閉包,可以從其周圍的上下文中捕獲值。

<code>Swift</code> 的閉包表達式具有幹淨、清晰的風格,其優化并鼓勵在常見場景中使用簡潔、整潔的文法。這些優化包括:

從上下文推斷參數和傳回值類型

單表達式閉包的隐式傳回

簡寫參數名稱

尾随閉包文法

閉包表達式文法具有以下一般形式,這跟很多進階程式設計語言的閉包寫法類似:

Swift 的标準庫提供了一個名為 的方法<code>sorted(by:)</code>,我們通過改方法簡單了解一下閉包的使用吧。

閉包作為函數參數進行傳遞,但是該閉包并未在函數傳回前調用,而是在函數傳回後才被調用,則這個閉包被稱為逃逸閉包。當我們聲明一個以閉包作為參數之一的函數時,我們可以在該閉包參數的類型之前書寫<code>@escaping</code>來表示該閉包允許逃逸。

舉個使用場景,當一個函數需要用到異步操作回調的時候需要使用逃逸閉包。 實作閉包逃逸的一種途徑是通過将該閉包存儲到定義在函數外面的變量中,稍後再去調用。

<code>autoclosure</code>是一個被自動建立的閉包,用于包裝作為參數傳遞給函數的表達式。該表達式被自動建立為:不含參數,傳回值省略(根據表達式的傳回值決定)<code>in</code>關鍵字省略,方法體中隻含表達式的閉包。

當該函數被調用時,自動閉包會傳回表達式的值。我們可以通過在函數類型前使用關鍵字<code>@autoclosure</code>把自動閉包外圍的花括号<code>{}</code>都給去掉。但是重點是使用<code>@autoclosure</code>關鍵字隻限于修飾參數中的閉包,并且該閉包的類型可以有傳回值,但絕對不能有參數。

使用關鍵字<code>@autoclosure</code>标記閉包參數為自動閉包類型的。調用函數時,傳遞閉包的實參時,可以像傳<code>String</code>類型的參數一樣而不是閉包那樣傳遞。

注意:過度使用<code>autoclosures</code>會使我們的代碼難以了解。上下文和函數名稱應該明确表示該閉包的調用被推遲了。 自動閉包同時也允許逃逸。需要同時使用<code>@autoclosure</code>和<code>@escaping</code>屬性。

閉包可以從定義它的周圍上下文中捕獲常量和變量。閉包可以在其方法體中引用并修改常量和變量的值,即使定義常量和變量的原始作用域不存在。 在 <code>Swift</code> 中,一個閉包可以捕獲值的最簡單形式就是嵌套函數。一個嵌套函數可以捕獲任何它外圍函數的參數也可以捕獲定義在外圍函數裡的常量和變量。

《Swift中閉包底層原理探索》

《Swift裡的高階函數》

《The Swift Programming Language》- Closures

下一篇: 1.1關于 Swift