Swift --閉包表示式與閉包(彙編分析)
在Swift中,可以通過func定義一個函式,也可以通過閉包表示式定義一個函式!
一、閉包表示式
概念
閉包表示式與定義函式的語法相對比,有區別如下:
- 去除了func
- 去除函式名
- 返回值型別添加了關鍵字in
- { }放在形參列表的前邊
閉包表示式的形式如下:
{ (引數列表) -> 返回值型別 in 函式體程式碼 }
講解
舉例1 閉包表示式作為變數或者常量的值
呼叫閉包表示式不需要寫引數v1,v2,直接呼叫fn0(10,20)就可以
舉例2 閉包表示式作為函式的返回值
舉例3 閉包表示式作為函式的實參
下面講述sorted(by:)方法定義和語法優化方式,來展示閉包表示式不同的表達方式達到同樣的效果!
講述之前先簡單介紹下sorted方法, Swift標準庫提供了sorted(by:)方法,會將已知型別陣列中的值進行排序. 一旦進行了排序會返回和原陣列大小相同,包含同類型元素並且是正確排序的陣列,如例3.
sorted(by:)方法接受一個閉包,該閉包函式需要傳入元素型別的兩個值,並返回Bool值,完成排序,排序閉包函式型別需為(String, String) -> Bool
在上面的兩種寫法中,都寫成了(String, String) -> Bool, 在閉包表示式中函式和返回值型別都寫在了大括號內,而不是大括號之外.
下面不斷簡化的如下
let arr = ["hello","world","guohai"] ///閉包表示式當做引數 //寫法一 let sortArr0 = arr.sorted{(str1: String, str2: String) -> Bool in return str1 < str2 } //寫法二: 省去了引數型別 let sortArr1 = arr.sorted{(str1, str2) -> Bool in return str1 < str2 } //寫法三: 如果返回值是單一表達式,可省去return let sortArr2 = arr.sorted{(str1, str2) -> Bool in str1 < str2 } //寫法四: 如果編譯器可以確定返回值,可以去除返回值型別 let sortArr3 = arr.sorted{(str1, str2) in str1 < str2 } //寫法四: Swift閉包表示式可以不明顯寫出引數名,可以用美元符$表示 let sortArr4 = arr.sorted{$0 < $1} //寫法五: 編譯器,對於$0 < $1和直接<效果一樣 let sortArr5 = arr.sorted(by: <)
尾隨閉包
如果將很長的閉包表示式作為函式的最後一個實參,使用尾隨閉包可以增強函式的可讀性
尾隨閉包是一個被書寫在函式呼叫括號外面(後面)的閉包表示式
如果閉包表示式是函式的唯一實參,而且使用了尾隨閉包的語法, 那就不需要在函式名後寫圓括號
二、閉包
閉包: 一個函式和它所捕獲的變數/常量環境組合起來
- 一般指定義在函式內部的函式
- 一般它捕獲的是外層函式的區域性變數/常量
看如下閉包,返回的plus和num形成了閉包
typealias Fn = (Int) -> Int func getFn() -> Fn { var num = 0 func plus(_ i: Int) ->Int { num += i return num } return plus } var fn = getFn() print(fn(1)) print(fn(2)) print(fn(3)) print(fn(4))
如果大家看不出上面的結果,可以將var num = 0放在外面是全域性變數,如下
全域性變數num時,結果是不斷的疊加,如果還是回到上一個,將num = 0移植到函式內部變成區域性變數,和plus形成閉包,結果又如何呢?
發現結果是一樣的,下面來探究本質!
檢視上面程式碼彙編程式碼如下
上面四次fn操作,呼叫訪問的同一記憶體num,因為閉包的作用將區域性變數num放進了堆空間,所以num不會被銷燬!
拓展:(iOS底層堆空間分配的大小是16的倍數--常識)
&n