簡體   English   中英

Swift可選的轉義閉包

[英]Swift optional escaping closure

在此處輸入圖片說明

編譯器錯誤Closure use of non-escaping parameter 'completion' may allow it to escape ,這是有道理的,因為它將在函數返回后調用。

func sync(completion:(()->())) {
    self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
        completion()
    }
}

但是,如果我將閉包設為可選,則不會出現編譯器錯誤,那是為什么呢? 函數返回后仍可以調用閉包。

func sync(completion:(()->())?) {
    self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
        completion?()
    }
}

將閉包包裝在Optional中會自動將其轉義。 從技術上講,它已經被嵌入枚舉(“可選”)“轉義”了。

澄清:

為了理解這種情況,實現以下代碼將很有用:

typealias completion = () -> ()

enum CompletionHandler {
    case success
    case failure

    static var handler: completion {
        get { return { } }
        set { }
    }
}

func doSomething(handlerParameter: completion) {
    let chObject = CompletionHandler.handler = handlerParameter
}

乍一看,此代碼似乎合法,但事實並非如此! 您將收到編譯時錯誤抱怨:

錯誤 :將非轉義參數'handlerParameter'分配給@轉義閉包

讓chObject = CompletionHandler.handler = handlerParameter

注意:

注意 :參數'handlerParameter'是隱式非轉義函數doSomething(handlerParameter:完成){

這是為什么? 假設代碼片段與@escaping沒有@escaping ...

實際上,由於Swift 3已發布,因此默認情況下,如果在enumstructclass中聲明了閉包,則閉包將被“轉義”。

作為參考,報告了與該問題有關的錯誤:

盡管它們可能與本案並非100%相關,但受讓人的評論清楚地描述了該案:

第一條評論

這里的實際問題是, 可選的閉包現在隱式@轉義。

第二條評論

不幸的是,Swift 3就是這種情況。這是Swift 3中轉義的語義:

1)默認情況下,函數參數位置的閉包不轉義

2) 所有其他關閉都在逃逸

因此,所有通用類型參數閉包(例如Array和Optional )都在轉義。

顯然, Optional是枚舉。

同樣-如上所述,相同的行為也適用於類和結構:

類案例:

typealias completion = () -> ()

class CompletionHandler {
    var handler: () -> ()

    init(handler: () -> ()) {
        self.handler = handler
    }
}

func doSomething(handlerParameter: completion) {
    let chObject = CompletionHandler(handler: handlerParameter)
}

結構案例:

typealias completion = () -> ()

struct CompletionHandler {
    var handler: completion
}

func doSomething(handlerParameter: completion) {
    let chObject = CompletionHandler(handler: handlerParameter)
}

上面的兩個代碼段將導致相同的輸出(編譯時錯誤)。

為了解決這個問題,您需要讓函數簽名為

func doSomething( handlerParameter: @escaping completion)


回到主要問題:

因為您期望您必須讓completion:(()->())? 為了逃脫,這將自動完成-如上所述-。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM