Swift可选的链接在闭包中不起作用

我的代码看起来像这样。 我的课有一个可选的变种

var currentBottle : BottleLayer? 

BottleLayer有一个方法jiggle()

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

 self.currentBottle?.jiggle() 

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

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

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

找不到会员'jiggle'

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

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

或者当然我可以使用全面的可选绑定,但我宁愿不。 我认识到,可选的链接只是语法上的糖,但是很难理解为什么这个语法上的糖只是因为它在一个处理程序中才会停止工作(尽pipe当然可能有一个原因 – 但无论如何,这是一个惊喜) 。

也许有人对此有所反应,并对此有所想法? 谢谢。

这不是一个错误。 这只是你的封闭types是错误的。 正确的types应该返回一个可选的Void来反映可选的链接:

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

详细问题:

  • 你把你的闭包声明为返回Void (即->() )的闭包。
  • 但是,请记住,就像每次使用可选的链接一样,整个expression式的返回types是可选的types 。 因为如果currentBottle存在,你的闭包可以返回Void或者如果不存在,则返回 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为你推断正确的types,而不是明确强制它,它会解决你的问题:

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

[编辑]

其他技巧:直接将可选的链接分配给一个variables

你甚至可以直接把函数赋值给一个variables,如下所示:

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

请注意,在这种情况下, clos2的types(这里没有明确指定,因此被Swift自动推断) 不是 Void->Void? – 也就是返回nil或者Void的函数),但是(Void->Void)? ,这是“ Void->Voidtypes的可选function”的types。

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

 clos2?() 

如果clos2本身nil (可能是因为currentBottle本身为零),并执行闭包(即currentBottle!.jiggle()代码),并返回Void如果clos2 )(可能是因为currentBottle本身是非零)。

clos2?()的返回types本身确实是Void? ,因为它返回零或无效。

VoidVoid?的区别Void? 可能看起来毫无意义(毕竟,在任何情况下,微动函数都不会返回任何东西),但是它可以让你执行像testingjiggle函数一样强大的functionVoid? 在一个if语句中检查这个调用是否真的发生了(并且返回Void即没有)或者没有发生(并且返回nil ):

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

当你(@matt)指出你自己的时候,这个另外的select还有另外一个重要的区别:当expression式被影响到clos2的时候,它计算currentBottle?.jiggle clos2 。 所以如果currentBottle当时nil ,那么clos2将是nil ,即使currentBottle得到非零值。

相反, clos对闭包本身也有影响,并且每次调用clos时都会对可选链进行评估,所以如果currentBottle为零,则评估为零,但是如果我们将评估为非零,并且将调用jiggle()在稍后调用clos() ,此时currentBottle变成非零。

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

否则,编译器认为该语句的结果应该从闭包中返回,并且它实现了() (返回types)和由语句( Optional<Void> )返回的可选项之间的不匹配。 通过添加一个明确的return ,编译器会知道我们不想返回任何东西。

错误信息当然是错误的。

好的,另一种方法 这是因为Swift中的闭包具有来自单expression式闭包的隐式返回 。 由于可选链,你的闭包有一个返回types的Void? ,所以:

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

让我们推断闭包types似乎也是可行的。

 let clos2 = { currentBottle?.jiggle() } clos2() // does a jiggle 

但我很确定这只是编译器分配() -> ()?