Swift 3必看:@noescape走了, @escaping來了

沒故事的卓同學發表於2019-03-02

在學習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才能編譯通過。

Swift 3必看:@noescape走了, @escaping來了

相關連結:
SE-0103:Make non-escaping closures the default

相關文章