当前位置: 首页 > 知识库问答 >
问题:

Swift @转义和完成处理程序

农鸿达
2023-03-14

我试图更准确地理解斯威夫特的“关闭”。

但是@escaping完成处理程序太难理解了

我搜索了许多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)

听说使用< code>@escaping有两种方式和原因

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

以下是我的问题:

首先,如果doThings执行,则一些FunctionSusEscape ingCloure将使用闭包参数执行,并且该闭包将保存在全局变量数组中。

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

{self.x=100}中保存在全局变量<code>completionHandlers</code>中的<code>self</code>如何连接到<code>实例</code>中<code>SomeClass</code>的对象?

其次,我理解了一些像这样的功能与回避关闭

要将局部变量闭包CompletionHandler存储到全局变量'CompletionHandler,我们使用@逃逸'关键字!

如果没有@转义关键字和带有转义闭包的somefunction返回,局部变量completionHandler,将从内存中删除

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

这样对吗?

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

也许这是一个非常初级的问题。

如果我们希望某个函数在某个特定函数之后执行。为什么我们不在特定函数调用后调用一些函数呢?

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

共有3个答案

司徒云
2023-03-14
/*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)*/
 
艾子石
2023-03-14

这里有一小部分例子,我用来提醒自己“逃避”是如何工作的。

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()
        }
    }

}
扶文光
2023-03-14

快速完成处理程序转义

正如Bob Lee在他的博客文章《与Bob一起的Swift》中解释的那样:

假设用户在使用应用时正在更新该应用。您肯定希望在完成后通知用户。你可能想弹出一个框,上面写着:“恭喜你,现在,你可能会完全享受!

那么,如何在下载完成后才运行一段代码呢?此外,如何在视图控制器被移动到下一个视图控制器之后才激活某些对象?好吧,我们将找出如何设计一个像老板一样的人。

根据我丰富的词汇表,完成处理程序代表

在事情完成时做事

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

@转义闭包:

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

有几种方法可以避免包含函数中的闭包:

> < li>

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

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

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

为了更清楚地了解这个话题,你可以在Medium上查看这个帖子。

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

  1. 转义闭包:转义闭包是在传递给返回的函数之后调用的闭包。换句话说,它的寿命超过了传递给它的函数。
  2. 非转义闭包:在传递给它的函数中调用的闭包,即在它返回之前。
 类似资料:
  • 我目前正在学习swift,几个小时以来我一直在试图理解一个错误。由于查询,我试图从php脚本中获取一个xml文件,我使用一个完成处理程序作为回调来获取这些查询的结果。 问题是我对这些技术感到不舒服,它说缺少论据。 下面是使用完成处理程序的函数: 这是我调用这个函数的一段代码: 这段代码显示有关调用连接的此错误: 我做错了什么?为什么它要两个参数? 非常感谢您的帮助。 埃尔巴托

  • 问题内容: 我正在试图做的是传递给函数,然后使用传递通过设置将返回。 我在中创建闭包时遇到了问题, 它引发了编译器错误/崩溃: 在斯威夫特,是根据文档应该包含的对象,就像Objective-C的版本。 这是我当前的代码: 编辑:似乎错误与不被视为数组有关。现在编译,但是我想集的时候得到什么,但无内。我检查了传递的,它们是有效的。 编辑2:打印后,我可以确认它返回了数据。但是仍然返回nil。 问题答

  • 问题内容: 我在Utilities类中使用loadImage方法,并且在通过闭包返回图像时遇到了一些麻烦。基本上因为我的代码可能返回图像或错误,所以在调用该方法时将其分配给image属性是行不通的。 我在类的方法声明中使用的方法是否错误,还是应该以不同的方式调用该方法以预期潜在的不同结果?谢谢 问题答案: 将处理程序添加到您的 loadImage 函数中: 迅捷3 像这样调用func: 斯威夫特2

  • 问题内容: 我是Swift和SpriteKit的新手。SpriteKit Actions的许多示例都在Objective C中,在Swift中我无法映射到它,也无法使用。 如果运行SKAction,并且在完成SKAction后又想做其他事情,那么如何在Swift中做到这一点呢? 任何想法将不胜感激。 编辑: 问题答案: 您的完成代码不会被调用,因为您的“死亡”操作将永远运行,这意味着它永远不会结束

  • 问题内容: 我正在创建一个返回Dictionary的,但是当我在另一个类中调用此方法时,其值为nil。 然后,我尝试在另一个类中调用它,以便可以查看Dictionary 的值并基于该值显示数据。例如, 这里的问题是,当我调用函数时,我在尝试调用字典时收到一个值。 简而言之,我的问题是如何为完成处理程序分配值并在Xcode项目中的其他位置调用它? 问题答案: 您的问题很乱。您的示例代码无效,并且没有

  • 问题内容: 我想知道如何为在Swift 3中创建的函数创建完成处理程序。这就是我在更新到Swift 3之前就完成函数的方式: 但是现在我无法找出目前可行的最佳方法。 问题答案: 在Swift 3中,闭包中的函数参数标签不见了。 删除所有出现并添加 并使用它