在學習Swift 3的過程中整理了一些筆記,如果想看其他相關文章可前往《Swift 3必看》系列目錄
在之前,一個函式的引數的閉包的捕捉策略預設是escaping,如果是一個非逃逸閉包需要顯示的新增宣告@noescape。感興趣的可以看我以前寫過一篇介紹:Swift中被忽略的@noescape。簡單的介紹就是如果這個閉包是在這個函式結束前內被呼叫,就是非逃逸的即noescape。如果這個閉包是在函式執行完後才被呼叫,呼叫的地方超過了這函式的範圍,所以叫逃逸閉包。
舉個例子就是我們常用的masonry或者snapkit的新增約束的方法就是非逃逸的。因為這閉包馬上就執行了。
public func snp_makeConstraints(file: String = #file, line: UInt = #line, @noescape closure: (make: ConstraintMaker) -> Void) -> Void {
ConstraintMaker.makeConstraints(view: self, file: file, line: line, closure: closure)
}複製程式碼
網路請求請求結束後的回撥的閉包則是逃逸的,因為發起請求後過了一段時間後這個閉包才執行。比如這個Alamofire裡的處理返回json的completionHandler閉包,就是逃逸的。
public func responseJSON(
queue queue: dispatch_queue_t? = nil,
options: NSJSONReadingOptions = .AllowFragments,
completionHandler: Response<AnyObject, NSError> -> Void)
-> Self
{
return response(
queue: queue,
responseSerializer: Request.JSONResponseSerializer(options: options),
completionHandler: completionHandler
)
}複製程式碼
就像我之前寫的那篇標題,很多人在寫閉包引數的時候總是忽略去判斷這個閉包是否是逃逸的。這對閉包的記憶體管理優化不太友好,都被當做了逃逸閉包處理。所以在3中做出了一個對調的改變:所有的閉包都預設為非逃逸閉包,不再需要@noescape;如果是逃逸閉包,就用@escaping表示。比如下面的一段程式碼,callBack在函式執行完後1秒才執行,所以是逃逸閉包。
func startRequest(callBack: ()->Void ) {
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 1) {
callBack()
}
}複製程式碼
這樣就需要顯示的宣告@escaping才能編譯通過。