Swift @escaping和Completion Handler

Don*_*Lee 80 closures escaping swift

我试图更准确地理解Swift的"关闭".

@escapingCompletion Handler太难以理解

我搜索了许多Swift帖子和官方文档,但我觉得还不够.

这是官方文档的代码示例

var completionHandlers: [()->Void] = []

func someFunctionWithEscapingClosure(completionHandler: @escaping ()->Void){
    completionHandlers.append(completionHandler)
}

func someFunctionWithNoneescapingClosure(closure: ()->Void){
    closure()
}

class SomeClass{
    var x:Int = 10
    func doSomething(){
        someFunctionWithEscapingClosure {
            self.x = 100
            //not excute yet
        }
        someFunctionWithNoneescapingClosure {
            x = 200
        }
    }
}

let instance = SomeClass()
instance.doSomething()
print(instance.x)

completionHandlers.first?() 
print(instance.x)
Run Code Online (Sandbox Code Playgroud)

我听说有两种使用方法和原因 @escaping

第一个用于存储闭包,第二个用于Async操作目的.

以下是我的问题:

首先,如果doSomething执行someFunctionWithEscapingClosure则将使用closure参数执行,并且该闭包将保存在全局变量数组中.

我认为封闭是{self.x = 100}

如何self在{self.x = 100}中保存在全局变量中completionHandlers可以连接到instance该对象SomeClass

其次,我这样理解someFunctionWithEscapingClosure.

将局部变量闭包存储completionHandler到全局变量'completionHandlers we using@escaping`关键字!

如果没有@escaping关键字someFunctionWithEscapingClosure返回,局部变量completionHandler将从内存中删除

@escaping 将关闭保留在内存中

这是正确的吗?

最后,我只是想知道这个语法的存在.

也许这是一个非常基本的问题.

如果我们想在某些特定函数之后执行某些函数.为什么我们不在特定函数调用后调用某些函数?

使用上述模式和使用转义回调函数有什么区别?

Sho*_*ari 103

首先,我想说"非常好的问题:)"

完成处理程序:

假设用户在使用它时正在更新应用程序.您肯定希望在完成后通知用户.你可能想要弹出一个框,上面写着:"恭喜,现在,你可以充分享受!"

那么,如何在下载完成后运行一段代码呢?此外,如何在视图控制器移动到下一个对象后才能为某些对象设置动画?好吧,我们将找出如何像老板一样设计一个.根据我的扩展词汇表,完成处理程序代表

事情已经完成时做的事情

有关详细信息,请访问此博客文章.

这个链接让我完全清楚完成处理程序(从开发人员的角度来看,它确切地定义了我们需要理解的内容).

@escaping闭包:

当您在函数的参数中传递闭包时,在函数的主体执行后使用它并返回编译器.当函数结束时,传递闭包的范围存在并且在内存中存在,直到闭包被执行.

在包含函数中有几种方法可以转义闭包:

  • 存储:当您需要将闭包存储在全局变量中时,属性或调用函数之前的内存中存在的任何其他存储都会被执行并返回编译器.

  • 异步执行:当你在despatch队列上异步执行闭包时,队列会为你保留内存中的闭包,以后可以使用.在这种情况下,您不知道何时将执行闭包.

当您尝试在这些场景中使用闭包时,Swift编译器将显示错误:

错误截图

有关此主题的更多信息,您可以在Medium上查看此帖子.

我希望你能从这个链接中得到很好的理解.

如果您仍然有任何问题(但请务必先逐行阅读此链接;这是非常好的解释)然后随时分享您的评论.

谢谢,如果这个答案需要更新,请继续发帖


小智 23

这是我用来提醒自己@escaping如何工作的一小部分例子.

class EscapingExamples: NSObject {

    var closure: (() -> Void)?

    func storageExample(with completion: (() -> Void)) {
        //This will produce a compile-time error because `closure` is outside the scope of this
        //function - it's a class-instance level variable - and so it could be called by any other method at
        //any time, even after this function has completed. We need to tell `completion` that it may remain in memory, i.e. `escape` the scope of this
        //function.
        closure = completion
        //Run some function that may call `closure` at some point, but not necessary for the error to show up.
        //runOperation()
    }

    func asyncExample(with completion: (() -> Void)) {
        //This will produce a compile-time error because the completion closure may be called at any time
        //due to the async nature of the call which precedes/encloses it.  We need to tell `completion` that it should
        //stay in memory, i.e.`escape` the scope of this function.
        DispatchQueue.global().async {
            completion()
        }
    }

    func asyncExample2(with completion: (() -> Void)) {
        //The same as the above method - the compiler sees the `@escaping` nature of the
        //closure required by `runAsyncTask()` and tells us we need to allow our own completion
        //closure to be @escaping too. `runAsyncTask`'s completion block will be retained in memory until
        //it is executed, so our completion closure must explicitly do the same.
        runAsyncTask {
            completion()
        }
    }





    func runAsyncTask(completion: @escaping (() -> Void)) {
        DispatchQueue.global().async {
            completion()
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 这段代码不正确。它缺少“@escaping”限定符。 (2认同)