Swift @转义和完成处理程序

tquggr8v  于 2022-11-21  发布在  Swift
关注(0)|答案(3)|浏览(143)

我试图更准确地理解斯威夫特的“关闭”。
但是@escapingCompletion Handler太难理解了
我搜索了许多斯威夫特的帖子和官方文件,但我觉得还是不够。
这是公文的代码示例

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将使用闭包参数执行,并且该闭包将保存在全局变量数组中。
我认为闭包是{self.x = 100}
{self.x = 100}中保存在全局变量completionHandlers中的self如何连接到SomeClass的那个对象instance
第二,我这样理解someFunctionWithEscapingClosure
将局部变量闭包completionHandler存放到全局变量'completionHandlers we using @'转义关键字!
如果没有@escaping关键字someFunctionWithEscapingClosure返回,则局部变量completionHandler将从内存中删除
@escaping将闭包保存在内存中
这是正确的吗?
最后,我只是想知道这种语法的存在。
也许这是一个非常基本的问题。
如果我们想让某个函数在某个特定的函数之后执行,为什么不直接在一个特定的函数调用之后调用它呢?
使用上面的模式和使用转义回调函数有什么区别?

yvgpqqbh

yvgpqqbh1#

Swift完成处理程序转义与非转义:

假设用户在使用应用程序时正在更新它,您肯定希望在更新完成时通知用户,您可能希望弹出一个框,上面写着“恭喜,现在,您可以完全享受了!”
那么,如何在下载完成后才运行一段代码呢?此外,如何在视图控制器移到下一个视图控制器后才对某些对象进行动画处理呢?我们将学习如何设计一个类似于老板的对象。
根据我丰富的词汇表,完成处理程序代表
“事情做完了再做"
Bob的帖子提供了关于完成处理程序的清晰说明(从开发人员的Angular 来看,它准确地定义了我们需要理解的内容)。

@转义闭包:

在函数参数中传递闭包时,在函数体执行并返回编译器后使用它。当函数结束时,传递的闭包的作用域存在并存在于内存中,直到闭包被执行。
有几种方法可以在包含函数中转义闭包:

  • 存储:当你需要将闭包存储在全局变量、属性或任何其他存在于调用函数的内存中的存储时,执行并返回编译器。
  • 异步执行:当你在发送队列上异步执行闭包时,队列会为你在内存中保存闭包,以备将来使用。在这种情况下,你不知道闭包何时会被执行。

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

有关此主题的详细信息,请参阅this post on Medium
再加上一点,这是每个ios开发人员都需要了解的:
1.逃逸闭合:转义闭包是在它被传递到的函数返回后被调用的闭包。换句话说,它比它被传递到的函数更长寿。
1.非逃逸封闭:一个闭包,在它被传入的函数中调用,即在它返回之前。

k3fezbri

k3fezbri2#

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

}
2j4z5cfb

2j4z5cfb3#

/*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)*/

相关问题