Swift 閉包表達式⑥

?在Swift中定義一個函數(shù)有兩種方式
??1. 可以通過func定義一個函數(shù)
??2. 通過閉包表達式
閉包格式:

{
(參數(shù)列表)-> 返回值 in
? 函數(shù)體代碼
}

示例:

//函數(shù)
func sum(_ v1 : Int , _ v2 : Int) -> Int {
    return v1 + v2
}
print(sum(1, 2)) //3

//閉包1
var fn = {
    (v1 : Int , v2 : Int) -> Int in
    return v1 + v2
}
print(fn(1,2)) //3
//閉包2
print({
    (v1 : Int , v2 : Int) -> Int in
    return v1 + v2
    }(20,30)) //50

1. 閉包表達式的簡寫

//函數(shù)定義
func exec(v1: Int, v2: Int , fn: (Int, Int) -> Int){
    print(fn(v1,v2))
}
//調(diào)用
exec(v1: 10, v2: 20, fn: {
    (v1, v2) -> Int in
    return v1 + v2
})

//2
exec(v1: 10, v2: 20, fn: {
    (v1, v2) in return v1 + v2
    }
)
//3
exec(v1: 10, v2: 20, fn: {
        (v1, v2) in  v1 + v2 //如果函數(shù)體代碼就是一個單一的表單時,則return可以省略
    }
)
//4
exec(v1: 10, v2: 20, fn: {$0 + $1})//$0 第一個參數(shù)

//5
exec(v1: 10, v2: 20, fn: + )

2. 尾隨閉包

  • 如果將一個很長的閉包表達式作為函數(shù)的最后一個實參,使用尾隨閉包可以增強函數(shù)的可讀性
  • 尾隨閉包是一個書寫在函數(shù)調(diào)用括號外面(后面)的閉包表達式
exec(v1: 10, v2: 20){
    (v1, v2) -> Int in
    return v1 + v2
}

exec(v1: 10, v2: 20){$0 + $1}
  • 如果閉包表達式是函數(shù)唯一實參,而且使用了尾隨閉包的語法,那就不需要在函數(shù)后面寫圓括號
func execc(fn : (Int, Int) -> Int){
    print(fn(1,2))
}

execc(fn: {
    (v1, v2) -> Int in
    return v1 + v2
    }
)

execc { (v1, v2) -> Int in
    return v1 + v2
}

execc{$0 + $1}

3. 自動閉包

為了避免與期望沖突,使用了@autoclosure 的地方最好明確注釋清楚:這個值會被推遲執(zhí)行


func getFirstPositive(_ v1: Int, _ v2: Int) -> Int {
    return v1 > 0 ? v1 : v2
}

getFirstPositive(10, 20)//10
getFirstPositive(-2, 20)//20
getFirstPositive(0, -4)//-4



func sum( ) -> Int {
    let a = 10
    let b = 10
    return a + b
}
getFirstPositive(10, sum())//對于這種情況,即便v1>0,后面的sum還是會執(zhí)行,浪費資源

//優(yōu)化
func getFirstPositive2(_ v1: Int, _ v2: ()->Int) -> Int {
    return v1 > 0 ? v1 : v2()
}

getFirstPositive2(10, {20})//10
getFirstPositive2(-2, {20})//20
getFirstPositive2(0, {-4})//-4
//autoclosure自動閉包  延遲加載
func getFirstPositive2(_ v1: Int, _ v2: @autoclosure()->Int) -> Int {
    return v1 > 0 ? v1 : v2()
}

getFirstPositive2(10, 20)//10
getFirstPositive2(-2, 20)//20
getFirstPositive2(0, -4)//-4
getFirstPositive2(2, sum())

  • @autoclosure 會自動將20 封裝成閉包 {20}
  • @autoclosure 只支持 ()-> T 格式的參數(shù)
  • @autoclosure 并非只支持最后一個參數(shù)
  • 空合并運算符?? 使用了- @autoclosure技術(shù)
  • @autoclosure 和 無@autoclosure構(gòu)成了函數(shù)重載

4. 非逃逸閉包、逃逸閉包

非逃逸閉包、逃逸閉包,一般都是當(dāng)做參數(shù)傳遞給函數(shù)

非逃逸閉包 :閉包調(diào)用發(fā)生在函數(shù)結(jié)束之前,閉包調(diào)用在函數(shù)作用域內(nèi)
逃逸閉包 :閉包有可能在函數(shù)結(jié)束后調(diào)用,閉包調(diào)用逃離了函數(shù)的作用域,需要通過@escaping 聲明

typealias Fn = () -> ()
//fn 是非逃逸閉包
func test1(_ fn : Fn)  {
    fn()
}

var gFn : Fn?
//fn 是逃逸閉包
func test2(_ fn: @escaping Fn)  {
    gFn = fn
}

//fn 是逃逸閉包
func test3(_ fn: @escaping Fn) {
    DispatchQueue.global().async {
        fn()// 異步,可能不再函數(shù)作用域
    }
}

閉包

  1. 一個函數(shù)和它所捕獲的變量/常量環(huán)境組合起來。稱為閉包,
  • 一般指定義在函數(shù)內(nèi)部的函數(shù)。
  • 一般它捕獲的是外層函數(shù)的局部變量/常量
typealias Fn = (Int) -> Int
func getFn() -> Fn{
  //局部變量 num
    var num = 0
    func plus(_ i:Int) -> Int{
      //被捕獲后,會在堆空間分配一個內(nèi)存用來存儲num
        num += i
        return num
    }
    return plus// 返回的plus 跟 捕獲的 num 組合起來叫做閉包,getFn只是一個函數(shù)
}
// 上面閉包的簡寫方式
func getFnS() -> Fn{
    var num = 0
    
    return {
        num += $0
        return num
    }
}

var fn1 = getFn()
var fn2 = getFn()
print(fn1(1))//1
print(fn2(2))//2
print(fn1(3))//4
print(fn2(4))//6
  1. 可以把閉包想象成一個類的實例對象
  • 內(nèi)存在堆空間
  • 捕獲的局部變量/常量就是對象的成員(存儲屬性)
  • 組成閉包的函數(shù)就是類內(nèi)部定義的方法
class Closure {
    var num = 0
    func plus(_ i: Int) -> Int {
        num += i
        return num
    }
    
}

var c1 = Closure()
var c2 = Closure()

c1.plus(1)//1
c2.plus(2)//2
c1.plus(3)//4
c2.plus(4)//6
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容