一尘不染

Swift可选链接在关闭时不起作用

swift

我的代码如下所示。我的课有一个可选的var

var currentBottle : BottleLayer?

BottleLayer有一个方法jiggle()

这段代码使用可选的链接,可以在我的类中很好地编译:

self.currentBottle?.jiggle()

现在,我想构造一个使用相同代码的闭包:

let clos = {() -> () in self.currentBottle?.jiggle()}

但是我得到一个编译错误:

找不到成员“ jiggle”

作为解决方法,我可以强制展开

let clos = {() -> () in self.currentBottle!.jiggle()}

或者我当然可以使用成熟的可选绑定,但是我宁愿不使用。我确实认识到可选链接只是语法糖,但是很难看出为什么这种语法糖会因为在处理程序中而停止工作(当然,这可能是有原因的,但无论如何这都是令人惊讶的)

也许其他人对此有所了解并对此有所考虑?谢谢。


阅读 174

收藏
2020-07-07

共1个答案

一尘不染

这不是错误。只是您的关闭类型有误。正确的类型应返回一个可选值Void以反映可选的链接:

let clos = { ()->()? in currentBottle?.jiggle() }

问题的细节:

  • 您将闭包声明为返回的闭包Void(即->())。
  • 但是,请记住,就像每次使用可选链接一样,整个表达式的返回类型都是 可选类型 。因为如果存在,您的关闭可以 返回VoidcurrentBottle …… 或者nil如果不存在,则 可以返回

因此正确的语法是使您的闭包返回Void?(或()?)而不是简单的Void

class BottleLayer {
    func jiggle() { println("Jiggle Jiggle") }
}
var currentBottle: BottleLayer?
currentBottle?.jiggle() // OK
let clos = { Void->Void? in currentBottle?.jiggle() } // Also OK
let clos = { () -> ()? in currentBottle?.jiggle() } // Still OK (Void and () are synonyms)

注意:如果让Swift为您推断正确的类型而不是显式强制使用它,它将为您解决此问题:

// Even better: type automatically inferred as ()->()? — also known as Void->Void?
let clos = { currentBottle?.jiggle() }

[编辑]

其他技巧:将可选链接直接分配给变量

您甚至可以将函数直接分配给变量,如下所示:

let clos2 = currentBottle?.jiggle // no parenthesis, we don't want to call the function, just refer to it

注意,类型clos2在此情况下(这是这里未明确指定,并且因此由夫特自动推断)是 Void->Void?
-即一个函数,返回任一nilVoid)如前面的情况下-但 (Void->Void)?,这是类型为“一种类型的 可选
功能Void->Void

这意味着它clos2本身就是“或者nil返回一个函数Void”。要使用它,您可以再次使用可选链接,就像这样:

clos2?()

nil如果clos2为本身nil(这可能是因为currentBottle本身为零),这将求值并且不执行任何操作……并执行闭包(因此为currentBottle!.jiggle()代码),Void如果clos2为非结果(则可能因为currentBottle自身为非零)而返回。

clos2?()本身的返回类型确实是Void?,因为它返回nil或Void。

Void和之间进行区分Void?似乎毫无意义(毕竟,在jiggle任何一种情况下该函数都不会返回任何内容),但是它可以让您执行强大的工作,例如Void?if语句中测试,以检查调用是否确实发生了(并且Void没有返回任何内容)或没有发生(并返回nil):

if clos2?() { println("The jiggle function got called after all!") }

[EDIT2]正如您(@matt)指出自己一样,另一种选择还有另一个主要区别:它currentBottle?.jiggle在表达式受到影响时进行评估clos2。所以,如果currentBottlenil在那个时候,clos2将是nil......即使currentBottle有一个非空值之后。

相反,clos它会影响闭包本身,并且仅在每次clos调用时都会评估可选链,因此它将评估nil是否currentBottle为nil…,但将评估为非nil,并且jiggle()如果我们clos()稍后再调用,则会进行调用。点currentBottle变成非零。

2020-07-07