Swift@转义和完成处理程序

Swift@转义和完成处理程序,swift,escaping,closures,Swift,Escaping,Closures,我试图更准确地理解Swift的“关闭” 但是@转义和完成处理程序太难理解了 我搜索了很多快捷的帖子和官方文件,但我觉得还不够 这是官方文件的代码示例 var completionHandlers: [()->Void] = [] func someFunctionWithEscapingClosure(completionHandler: @escaping ()->Void){ completionHandlers.append(completionHandler) }

我试图更准确地理解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)
我听说有两种方法和理由使用
@escaping

第一个用于存储闭包,第二个用于异步操作

以下是我的问题

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

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

保存在全局变量
completionHandlers
中的{self.x=100}中的
self
如何连接到
实例
某个类的对象

第二,我理解
一些带有EscapingClose的函数

要将局部变量closure
completionHandler
存储到全局变量completionHandler
中,我们使用
@escaping`关键字

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

@escaping
是将闭包保存在内存中

是这样吗

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

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

如果我们想在某个特定函数之后执行某个函数。为什么我们不在特定的函数调用之后调用某个函数呢


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

快速完成处理程序转义和非转义:

正如Bob Lee在他的博客文章中所解释的:

假设用户在使用应用程序时正在更新应用程序。你肯定想要 完成时通知用户。你可能想弹出一个盒子 也就是说,“恭喜你,现在,你可以尽情享受了!”

那么,如何仅在下载完成后运行代码块呢 完整的?此外,如何仅在一个动画之后设置某些对象的动画 视图控制器是否已移动到下一个?好吧,我们会找到的 如何设计一个像老板一样的

根据我的扩展词汇表,补全处理程序代表

事情完成后再做

Bob的文章提供了关于完成处理程序的清晰信息(从开发人员的角度来看,它准确地定义了我们需要理解的内容)

@转义闭包:

在函数参数中传递闭包时,在函数体执行并返回编译器后使用闭包。当函数结束时,传递的闭包的作用域在内存中存在,直到执行闭包为止

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

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

  • 异步执行:当您在调度队列上异步执行闭包时,队列将为您保存内存中的闭包,以便将来使用。在这种情况下,您不知道何时执行闭包

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

有关此主题的更多信息,请查看

添加每个ios开发人员都需要了解的一点:

  • 转义闭包:转义闭包是在传递给它的函数返回后调用的闭包。换句话说,, 它比传递给它的函数更有效
  • 非转义闭包:在传递到的函数中调用的闭包,即在返回之前调用的闭包

  • 下面是我用来提醒自己@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()
            }
        }
    
    }
    

    @shabhakar,如果我们存储了一个关闭,但以后不调用它呢。或者若方法被调用了两次,但我们只调用了一次闭包。因为我们知道结果是一样的。@user1101733我想你们说的是转义闭包,闭包在你们不调用之前不会执行。在上面的示例中,如果调用doSomething方法2乘以2 completionHandler对象,则该对象将添加到completionHandlers数组中。若从completionHandlers数组中获取第一个对象并调用它,它将执行,但completionHandlers数组计数将保持不变(2)。@Deepak,是关于转义闭包。假设我们不使用数组,而是使用普通变量来存储闭包引用,因为我们需要执行最近的调用。以前的闭包是否会占用一些永远不会调用的内存?@user1101733闭包是引用类型(如类),当您将新闭包分配给变量时,属性/变量将指向新闭包,因此ARC将为以前的闭包释放内存。此代码不正确。它缺少
    @escaping
    限定符。我最喜欢这个
    ,也就是说,转义这个函数的作用域。
    “预期参数类型如下:”
    /*the long story short is that @escaping means that don't terminate the function life time until the @escaping closure has finished execution in the opposite of nonEscaping closure the function can be terminated before the closure finishes execution Ex:
    */
    
     func fillData(completion: @escaping: () -> Void){ 
         /// toDo 
        completion()
      }
    
    //___________________________
    
    //The call for this function can be in either way's @escaping or nonEscaping :
    
        
    fillData{
     /// toDo
    }
        
    
    /* again the deference between the two is that the function can be terminated before finish of execution nonEscaping closure in the other hand the @escaping closure guarantees that the function execution will not be terminated before the end of @escaping closure execution. Hope that helps ***#(NOTE THAT THE CLOSURE CAN BE OF ANY SWIFT DATA TYPE EVEN IT CAN BE TYPEALIAS)*/