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

时间:2014-06-09 17:13:39

标签: ios swift

我的代码看起来像这样。我的班级有一个可选的var

var currentBottle : BottleLayer?

BottleLayer有一个方法jiggle()

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

self.currentBottle?.jiggle()

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

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

但是我收到编译错误:

  

找不到会员' jiggle'

作为一种解决方法,我可以强制解包

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

当然我可以使用完整的可选绑定,但我不愿意。我确实认识到可选链接只是语法糖,但很难理解为什么这种语法糖会因为它处理器而停止工作(当然,这可能是一个原因 - 但它&#39 ;无论如何都是惊喜。)

也许其他人已经闯入这个并对此有所想法?感谢。

4 个答案:

答案 0 :(得分:19)

这不是一个错误。它只是你的闭包类型是错误的。 正确的类型应返回可选的Void以反映可选的链接:

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

详细问题:

  • 您将闭包声明为一个返回Void的闭包(即->())。
  • 但是,请记住,就像每次使用可选链接一样,整个表达式的返回类型是的可选类型。因为如果Void确实存在,可以返回currentBottle ... 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的类型(此处未明确指定,因此由Swift自动推断)在这种情况下 Void->Void? - 即一个函数返回nilVoid),与前一种情况相同 - 但(Void->Void)? ,这是&#34; 可选<的类型/ strong>类型Void->Void的功能&#34;。

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

clos2?()

这将评估为nil,如果clos2本身为nil,则不执行任何操作(可能因为currentBottle本身为零)...并执行闭包 - 因此{{ 1}}代码 - 如果currentBottle!.jiggle()非零,则返回Void(可能因为clos2本身不为零)。

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

区分Void?Void可能看起来毫无意义(毕竟,Void?函数在任何一种情况下都不会返回任何内容),但它可以让你做一些强大的事情,比如测试jiggle语句中的Void?来检查调用是否确实发生(并且返回if即没有)或者没有发生(并且返回Void):

nil

[EDIT2]正如您(@matt)指出的那样,另一个替代方案还有另一个主要区别:它在表达式受if clos2?() { println("The jiggle function got called after all!") } 影响时评估currentBottle?.jiggle。因此,如果当时clos2currentBottle,则nil将为clos2 ...即使nil稍后获得非零值。

相反,currentBottle会对闭包本身产生影响,并且每次调用clos时都会评估可选链接,因此如果clos它将评估为nil是零......但如果我们稍后调用currentBottle jiggle()变为非零,则会被评估为非零,并且会调用clos()

答案 1 :(得分:7)

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

否则编译器认为应该从闭包返回该语句的结果,并且它意识到()(返回类型)与语句(Optional<Void>)返回的可选项之间存在不匹配。通过添加显式return,编译器将知道我们不想返回任何内容。

错误信息当然是错误的。

答案 2 :(得分:1)

好的,另一种方法。这是因为Swift中的闭包具有单表达式闭包的隐式返回。由于可选链,您的闭包的返回类型为Void?,因此:

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

答案 3 :(得分:0)

让推断闭包类型似乎也有效。

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

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

的类型