代码之家  ›  专栏  ›  技术社区  ›  Bilal hao zou

Swift可选逃逸闭合

  •  14
  • Bilal hao zou  · 技术社区  · 7 年前

    enter image description here

    编译器错误 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?()
        }
    }
    
    2 回复  |  直到 7 年前
        1
  •  26
  •   Rob Napier    7 年前

    将闭包包装在可选中会自动标记其转义。从技术上讲,它已经通过嵌入enum(可选)进行了“转义”。

        2
  •  20
  •   Ahmad F    7 年前

    澄清:

    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=handler参数

    注意:

    笔记 :参数“handlerParameter”是隐式非转义func 剂量测定(Handler参数:完成){

    为什么?假设代码片段与 @escaping ...

    事实上,由于Swift 3已经发布,如果在 枚举 , 结构 默认情况下。

    作为参考,报告了与此问题相关的错误:

    First comment :

    这里的实际问题是 可选闭包是隐式的 @马上逃跑。

    Second comment :

    不幸的是,Swift 3就是这样。以下是 在Swift 3中逃跑:

    1) 函数参数位置的闭包是 默认情况下不转义

    2) 所有其他关闭正在逃逸

    因此,所有泛型类型参数闭包,例如数组和 可选择的 ,正在逃跑。

    明显地 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:(()->())? 如前所述,这将自动完成。