Swift中带括号的闭包的输入参数

Posted

技术标签:

【中文标题】Swift中带括号的闭包的输入参数【英文标题】:Input parameter to closure in Swift with brackets 【发布时间】:2018-04-05 01:59:37 【问题描述】:

我正在阅读RxSwift上的以下教程:

http://adamborek.com/thinking-rxswift/

并且无法理解以下模式:

           searchBar.rx.text.orEmpty
------------> .flatMap  [spotifyClient] query in
                   return spotifyClient.rx.search(query: query)
             .map  tracks in
                   return tracks.map(TrackRenderable.init)
             

这个方括号输入参数:[spotifyClient] query 对我来说似乎很奇怪。我查看了官方Apple 文档中的闭包和函数,但我看不到任何此类输入参数的示例。在Objective C 中,这不会打扰我,但它是Swift。谁能解释一下,这个参数在这里是什么意思?

【问题讨论】:

它是一个捕获列表,用于将对象的副本复制到其块中 【参考方案1】:

您需要了解闭包的变量捕获的想法。

考虑这个例子:

struct Calculator 
    var a: Int
    var b: Int

    var sum: Int 
        return a + b
    

然后你将它用作:

let calculator = Calculator(a: 3, b: 5)

// You define a closure where you will use this calculator instance
let closure = 
    // closure captures the variables that are declared prior to the declaration of the closure.
    // your calculator instance is being captured here
    // it's default variable capture
    print("The result is \(calculator.sum)")


closure() // Prints "The result is 8"

到目前为止,一切都很好。你得到了预期的结果。

现在考虑将计算器实例声明为var,因为在某些时候您需要改变它的状态。这就是复杂性出现的情况。看:

var calculator = Calculator(a: 3, b: 5)

let closure = 
    print("The result is \(calculator.sum)")


// You change the state of your calculator instance anytime before the closure gets executed
calculator.b = 20
// When the closure actually executes, you will be affected by any changes outside the closure 
closure() // Prints "The result is 23"

因此,默认变量捕获并没有真正帮助您,而是在您的情况下造成问题。


如果您想阻止这种行为并打印 8,即使属性在闭包内捕获后发生变化,我们也可以使用 捕获列表 em> 像这样:

// [calculator] is your capture list
let closure =  [calculator] in
    print("The result is \(calculator.sum)")

// change anything with calculator instance
calculator.b = 20
// execute the closure
closure() // Prints "The result is 8"

捕获列表保留变量的不可变副本。感谢这个副本,在闭包之外对计算器的进一步更改不会影响闭包。

您可以一次捕获多个变量,因此称为捕获列表。示例:

let closure =  [variable1, variable2, variable3] in
    print(variable1)
    print(variable2)
    print(variable3)

我推荐你阅读这篇文章Capturing Values In Swift Closures。



现在,在您的情况下,spotifyClient 是一个可能负责进行 API 调用的类的实例。此实例可能需要一些更改才能调用不同的 API。因此,为了防止在此闭包之外对 spotifyClient 的任何更改产生影响,您可以在 Capture List 中捕获此实例。



捕获列表与参数列表:

您将参数列表与捕获列表混淆了。通用语法是:

 [capture list] (parameter list) in
    ...
    ...

现在看看上面例子的修改版本:

let closure: (String)-> Void =  [calculator] stringParameter in // When using single parameter, you can always omit the () parentheses
    print("\(stringParameter). The result is \(calculator.sum)")


// change anything with calculator instance
calculator.b = 20
// execute the closure
closure("Hey") // Prints "Hey. The result is 8"

【讨论】:

好的,但是'query'参数在那里做什么?它是第二个参数吗?为什么没有逗号? 您的spotifyClient 是捕获列表的元素之一。而query 是一个参数。他们不一样。查看我的最新编辑。

以上是关于Swift中带括号的闭包的输入参数的主要内容,如果未能解决你的问题,请参考以下文章

Swift学习笔记-函数和闭包

方括号中带有(属性)的方法参数

《从零开始学Swift》学习笔记(Day 23)——尾随闭包

SWIFT 中带有自定义参数的发布请求

为啥速记参数名称在这个 Swift 闭包中不起作用?

Swift 5:转义闭包捕获'inout'参数