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

更新到 Swift 3 的闭包 - @escaping

尹俊贤
2023-03-14

我已经将我的代码更新到Xcode 8.0 beta 6,但我陷入了关于新的非转义闭包默认值的困境。在下面的代码中,Xcode建议在完成之前添加@escaping在下面代码的第一行中,但这仍然不会编译并循环。*

(编辑:事实上,@escaping应该在完成后添加:,正如Xcode所建议的那样。警报可能仍会显示,但清理和编译会将其删除。* 如何重写/修复此代码才能在更新的 Swift 3 中工作?我已经查看了新手册,但我找不到正确的代码示例。

func doSomething(withParameter parameter: Int, completion: () -> ()) {
    // Does something

    callSomeOtherFunc(withCompletion: completion)
  }

// Calling the method and execute closure 
doSomething(withParameter: 2) {
  // do things in closure
}

任何帮助非常感谢!

共有2个答案

夹谷鸿福
2023-03-14

从xcode 8 beta 6 < code > @ no escape 是默认的。在此之前,< code>@escaping是默认设置。任何从以前版本升级到swift 3.0的人都可能会遇到这个错误。

不能在变量中存储@noescape闭包。因为如果可以在变量中存储闭包,则可以从代码中的任何位置执行闭包。但@noescape声明闭包参数不能转义函数的主体。

这将导致Xcode 8中的编译器错误

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: () -> ()) {
        myClosure = finishBlock    // ‼️ Error: Assigning non-escaping parameter 'finishBlock' to an @escaping closure
    }
}

这将编译正常(显式写入@escaping

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: @escaping () -> ()) {
        myClosure = finishBlock
    }
}

@noescape的好处:

    < li >编译器可以优化您的代码以获得更好的性能 < li >编译器可以负责内存管理 < li >不需要在闭包中使用对self的弱引用


有关详细信息,请查看:将非转义闭包设为默认值

燕扬
2023-03-14

在Swift 3之前,闭包属性< code>@autoclosure和< code>@noescape以前是闭包参数的属性,现在是参数类型的属性;请参见以下已被接受的Swift evolution提案:

    < li>SE-0049:将@noescape和@autoclosure移动到be类型属性中

您的具体问题与参数类型属性< code>@escaping(适用相同的新规则)有关,正如已被接受的Swift evolution提案中所述,默认情况下闭包参数是不可转义的:

  • SE-0103:将非转义闭包设为默认值

这些建议现在都在Xcode 8的beta阶段实现(请参阅Xcode 8 beta 6的发行说明;开发人员。访问所需的帐户登录)

Xcode 8 beta 6中的新版本-Swift编译器:Swift语言

默认情况下,闭包参数是非转义的,而不是显式地使用@noscape进行注释。使用@逃逸指示闭包参数可以转义。@自动闭包(转义)现在编写为@自动闭包@转义。不建议使用注释@noscape@自动闭包(转义)。(SE-0103)

...

Xcode 8测试版中的新功能–Swift和Apple LLVM编译器:Swift语言

@noescape@autoclosure属性现在必须写在参数类型之前,而不是参数名称之前。〔SE-0049〕

因此,您使用非默认的@转义属性,如下所示;应用于闭包参数的类型,而不是参数本身

func doSomething(withParameter parameter: Int, completion: @escaping () -> ()) {
    // ...
}

(包括我在下面一个投票赞成的评论中对一个问题的回答,因为评论不是SO上的持久数据)

@Cristi Băluț259:“转义做什么?在swift3自动转换之前从未见过这个关键字…”

例如,请参阅上面SE-0103演进提案的链接(以及beta 6发行说明中引用的文本):以前,闭包参数默认情况下是转义的(因此不需要存在转义的显式注释),但现在默认情况下是不转义的。因此添加了@eving来显式注释闭包参数可以转义(与其默认行为相反)。这也解释了为什么@noscape现在已弃用(无需注释默认行为)。

为了解释闭包参数转义的含义,我引用了语言引用-属性:

“将此属性应用于方法或函数声明中的参数类型,以指示可以存储参数值以供以后执行。这意味着允许该值超过调用的生存期。”

 类似资料:
  • 我正在使用Equinox构建一个OSGi应用程序。对于这个应用程序来说,可以更新各个bundle是至关重要的。 应用程序检查HTTP服务器上的文件夹中是否有新版本的捆绑包,以及是否有任何新捆绑包可用。如果有新的包可用,应用程序将加载*. jar文件并更新此包。更新是通过停止捆绑包,用加载文件的输入流更新它,然后再次启动捆绑包来执行的。 问题是,在更新文件和重新启动应用程序后,文件的旧版本被使用,而

  • 问题内容: 在学习Swift时,我正在编写一个简单的实践iOS应用程序,以从站点中抓取给定城市的天气信息,并将其显示在UILabel中。 该代码使用“ NSURLSession.sharedSession()。dataTaskWithURL”闭包。尽管我能够正确获取数据并在“ UILabel.text”中捕获相关文本,但是我无法获得实际的应用程序来显示更新的UILabel。 我究竟做错了什么?以下

  • Rust 的闭包实现与其它语言有些许不同。它们实际上是trait的语法糖。在这以前你会希望阅读trait章节,和trait对象。 都理解吗?很好。 理解闭包底层是如何工作的关键有点奇怪:使用()调用函数,像foo(),是一个可重载的运算符。到此,其它的一切都会明了。在Rust中,我们使用trait系统来重载运算符。调用函数也不例外。我们有三个trait来分别重载: # mod foo { pub

  • 基本形式 闭包看起来像这样: let plus_one = |x: i32| x + 1; assert_eq!(2, plus_one(1)); 我们创建了一个绑定,plus_one,并把它赋予一个闭包。闭包的参数位于管道(|)之中,而闭包体是一个表达式,在这个例子中,x + 1。记住{}是一个表达式,所以我们也可以拥有包含多行的闭包: let plus_two = |x| { let

  • 问题内容: 我正在尝试遵循Apple的“ 开始开发iOS应用程序(Swift)”教程,并且几乎完成了该教程。当我使用Xcode 8(我认为使用Swift 3而不是Swift 2)时,不得不修改本教程的几个部分。但是,我遇到了以下编译器错误,我不知道为什么: 在以下功能中: 我猜想有一个不同的NSIndexPath初始化程序在Swift 3中已更改,但我找不到它。难道我做错了什么? 谢谢, 问题答案

  • 与其他包管理器(如)相比,我发现当更新与给定项目相关的包时,有一种奇怪的行为。 还根据留档,和选项 根据composer.json将依赖项升级到最新版本,并更新composer.lock文件。 事实上,正确地更新了新的包版本号。但是没有被修改,并且列出了旧的版本过低的包。 为什么会发生这种情况?是我做错了什么,还是这就是应该怎么做的?如果是这样的话,为什么两个文件中的一个是最新的,而另一个不是最新