我的代码如下所示。我的课有一个可选的var
var currentBottle : BottleLayer?
BottleLayer有一个方法jiggle()。
jiggle()
这段代码使用可选的链接,可以在我的类中很好地编译:
self.currentBottle?.jiggle()
现在,我想构造一个使用相同代码的闭包:
let clos = {() -> () in self.currentBottle?.jiggle()}
但是我得到一个编译错误:
找不到成员“ jiggle”
作为解决方法,我可以强制展开
let clos = {() -> () in self.currentBottle!.jiggle()}
或者我当然可以使用成熟的可选绑定,但是我宁愿不使用。我确实认识到可选链接只是语法糖,但是很难看出为什么这种语法糖会因为在处理程序中而停止工作(当然,这可能是有原因的,但无论如何这都是令人惊讶的) 。
也许其他人对此有所了解并对此有所考虑?谢谢。
这不是错误。只是您的关闭类型有误。正确的类型应返回一个可选值Void以反映可选的链接:
Void
let clos = { ()->()? in currentBottle?.jiggle() }
->()
currentBottle
nil
因此正确的语法是使您的闭包返回Void?(或()?)而不是简单的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? -即一个函数,返回任一nil或Void)如前面的情况下-但 是(Void->Void)?,这是类型为“一种类型的 可选 功能Void->Void。
clos2
Void->Void?
(Void->Void)?
Void->Void
这意味着它clos2本身就是“或者nil返回一个函数Void”。要使用它,您可以再次使用可选链接,就像这样:
clos2?()
nil如果clos2为本身nil(这可能是因为currentBottle本身为零),这将求值并且不执行任何操作……并执行闭包(因此为currentBottle!.jiggle()代码),Void如果clos2为非结果(则可能因为currentBottle自身为非零)而返回。
currentBottle!.jiggle()
clos2?()本身的返回类型确实是Void?,因为它返回nil或Void。
在Void和之间进行区分Void?似乎毫无意义(毕竟,在jiggle任何一种情况下该函数都不会返回任何内容),但是它可以让您执行强大的工作,例如Void?在if语句中测试,以检查调用是否确实发生了(并且Void没有返回任何内容)或没有发生(并返回nil):
jiggle
if
if clos2?() { println("The jiggle function got called after all!") }
[EDIT2]正如您(@matt)指出自己一样,另一种选择还有另一个主要区别:它currentBottle?.jiggle在表达式受到影响时进行评估clos2。所以,如果currentBottle是nil在那个时候,clos2将是nil......即使currentBottle有一个非空值之后。
currentBottle?.jiggle
相反,clos它会影响闭包本身,并且仅在每次clos调用时都会评估可选链,因此它将评估nil是否currentBottle为nil…,但将评估为非nil,并且jiggle()如果我们clos()稍后再调用,则会进行调用。点currentBottle变成非零。
clos
clos()