Swift iOS : @escaping 屬性

RecoReco發表於2017-06-01

使用閉包,有兩種情況,一種是在呼叫者完成前閉包就被執行完成了。還有一種則相反:呼叫函式完成了,但是閉包還沒有被呼叫或者沒有被完成。後者被稱為逃逸閉包。

所有網路請求的函式,在完成呼叫請求後,直到響應返回,閉包才會被呼叫,所以這個型別的網路請求函式內等待響應的閉包就是逃逸閉包。這個型別的閉包,需要程式設計師手工加入一個@escaping標記才可以編譯通過。

如下程式碼,展示了一個非逃逸閉包,和一個逃逸閉包。後者已經被標記了@escapings:

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window : UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        func syncRequest(callBack: ()->Void ) {
            callBack()
        }
        func asyncRequest( callBack: @escaping()->Void ) {
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
                callBack()
            })
        }
        syncRequest(){
            print("callback")
        }
        asyncRequest(){
            print("delay 1s callback")
        }
        window = UIWindow()
        window!.rootViewController = UIViewController()
        window!.rootViewController!.view.backgroundColor = .blue
        window!.makeKeyAndVisible()
        return true
    }
}複製程式碼

函式DispatchQueue.main.asyncAfter用來延時。此處延時1s再呼叫callback,演示了一個逃逸閉包的效果。

閉包可能需要引用當前上下文的變數,因此當呼叫者完成後,如果標記了逃逸閉包,那麼當前呼叫的上下文依然會保持。如果在該標記的地方沒有標記的話,會怎麼樣?不會在執行時報錯,而是在編譯期間就報錯了。

因為編譯器知道你沒有立即呼叫callback。好智慧。

然而,既然知道這種情況下,我需要標記@escaping,幹麼不直接做了?我暫時還無法回答這個問題,或者你知道?

相關文章