1. 程式人生 > >Swift @escaping @ noescaping 逃逸閉包與非逃逸閉包

Swift @escaping @ noescaping 逃逸閉包與非逃逸閉包

閉包只有在函式中做引數時才會區分逃逸閉包和非逃逸閉包。

Swift 3.0之後,傳遞閉包到函式中的時候,系統會預設為非逃逸閉包型別(NonescapingClosures)@noescaping,逃逸閉包在閉包前要新增@escaping關鍵字。

從生命週期看兩者區別:

非逃逸閉包的生命週期與函式相同:

1,把閉包作為引數傳給函式;

2,函式中呼叫閉包;

3,退出函式。結束

逃逸閉包的生命週期:

1,閉包作為引數傳遞給函式;

2,退出函式;

3,閉包被呼叫,閉包生命週期結束

即逃逸閉包的生命週期長於函式,函式退出的時候,逃逸閉包的引用仍被其他物件持有,不會在函式結束時釋放

例如:

非逃逸閉包:


程式碼執行順序(1),(2),(3)

當傳遞閉包引數給函式loadData時,要注意ViewController中的屬性tools,雖然閉包會捕獲self,但是由於預設閉包引數是非逃逸型,這裡可以省略self,編譯器已經知道這裡不會有迴圈引用的潛在風險。

逃逸閉包:


程式碼執行順序:(1),(3),(2)

當傳遞閉包引數給函式loadData時,要注意ViewController中的屬性tools,這裡閉包函式的生命週期在函式結束後結束,tools前面省略的self 就有必要做特殊處理,防止造成死迴圈。逃逸閉包前面新增@escaping關鍵字,這裡閉包的生命週期不可預知。

經常使用逃逸閉包的2個場景:

  1. 非同步呼叫: 如果需要排程佇列中非同步呼叫閉包,比如網路請求成功的回撥和失敗的回撥,
    這個佇列會持有閉包的引用,至於什麼時候呼叫閉包,或閉包什麼時候執行結束都是不確定,上邊的例子。
  2. 儲存: 需要儲存閉包作為屬性,全域性變數或其他型別做稍後使用,例子待補充。