閉包隻有在函數中做參數時才會區分逃逸閉包和非逃逸閉包。
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個場景:
- 異步調用: 如果需要排程隊列中異步調用閉包,比如網絡請求成功的回調和失敗的回調,這個隊列會持有閉包的引用,至于什麼時候調用閉包,或閉包什麼時候運作結束都是不确定,上邊的例子。
- 存儲: 需要存儲閉包作為屬性,全局變量或其他類型做稍後使用,例子待補充。