1. 程式人生 > >Swift --閉包表示式與閉包(彙編分析)

Swift --閉包表示式與閉包(彙編分析)

在Swift中,可以通過func定義一個函式,也可以通過閉包表示式定義一個函式!

一、閉包表示式

概念

閉包表示式與定義函式的語法相對比,有區別如下:

  1. 去除了func
  2. 去除函式名
  3. 返回值型別添加了關鍵字in
  4. { }放在形參列表的前邊

閉包表示式的形式如下:

{ 

   (引數列表) -> 返回值型別 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