Swift可选链接在关闭时不起作用 [英] Swift optional chaining doesn't work in closure

查看:108
本文介绍了Swift可选链接在关闭时不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My code looks like this. My class has an optional var

var currentBottle : BottleLayer?

BottleLayer的方法 jiggle()

BottleLayer has a method jiggle().

此代码使用可选链接,在我的课程中编译良好:

This code, using optional chaining, compiles fine in my class:

self.currentBottle?.jiggle()

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

Now I want to construct a closure that uses that same code:

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

但是我收到编译错误:


找不到会员'jiggle'

Could not find member 'jiggle'

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

As a workaround I can force unwrapping

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

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

or of course I can use full-fledged optional binding, but I'd rather not. I do recognize that optional chaining is just syntactical sugar, but it is hard to see why this syntactical sugar would stop working just because it's in a handler (though there may, of course, be a reason - but it's a surprise in any case).

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

Perhaps someone else has banged into this and has thoughts about it? Thanks.

推荐答案

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

This is NOT a bug. It's simply your closure type which is wrong. The correct type should return an optional Void to reflect the optional chaining:

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






问题详情:




  • 您将闭包声明为一个返回 Void 的闭包(即 - >())。

  • 但是,请记住,就像每次使用可选链接一样,返回类型为整个表达式是的可选类型。因为你的关闭可以返回 Void 如果 currentBottle 确实存在... nil 如果没有!


  • The problem in details:

    • You declare your closure as a closure that returns Void (namely ->()).
    • But, do remember that, as like every time you use optional chaining, the return type of the whole expression is of optional type. Because your closure can either return Void if currentBottle do exists… or nil if it doesn't!
    • 所以正确的语法是让你的闭包返回 Void?(或()?)而不是简单的 Void

      So the correct syntax is to make your closure return a Void? (or ()?) instead of a simple 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为你推断出正确的类型而不是明确地强迫它,它会为你解决问题:

      Note: if you had let Swift infer the correct type for you instead of explicitly forcing it, it would have fixed the issue for you:

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







      你甚至可以将函数直接赋值给变量,如下所示:

      You can even assign the function directly to a variable, like so:

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

      注意<$ c的类型$ c> clos2 (这里没有明确指定,因此由Swift自动推断)在这种情况下 Void-> Void? - 即返回 nil Void )的函数,与前一种情况一样 - 但是(Void-> Void)? ,这是类型<的可选函数的类型code> Void-> Void 。

      Note that the type of clos2 (which is not explicitly specified here and is thus inferred automatically by Swift) in this case is not Void->Void? — namely a function that returns either nil or Void) as in the previous case — but is (Void->Void)?, which is the type for "an optional function of type Void->Void".

      这意味着 clos2 本身是要么 nil ,要么就是函数n返回无效。要使用它,您可以再次使用可选链接,就像这样:

      This means that clos2 itself is "either nil or is a function returning Void". To use it, you could once again use optional chaining, simply like that:

      clos2?()
      

      这将评估为 nil ,如果 clos2 本身是 nil (可能是因为 currentBottle 本身为零)...并执行关闭 - 因此 currentBottle!.jiggle()代码 - 如果 clos2 <返回 Void / code>是非零的(可能是因为 currentBottle 本身是非零的。)

      This will evaluate to nil and do nothing if clos2 is itself nil (likely because currentBottle is itself nil)… and execute the closure — thus the currentBottle!.jiggle() code — and return Void if clos2 is non-nil (likely because currentBottle itself is non-nil).

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

      The return type of clos2?() itself is indeed Void?, as it returns either nil or Void.

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

      Doing the distinction between Void and Void? may seem pointless (after all, the jiggle function does not return anything in either case), but it let you do powerful stuff like testing the Void? in an if statement to check if the call actually did happen (and returned Void namely nothing) or didn't happen (and return nil):

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






      正如你(@matt)指出的那样,这另一种选择还有一个主要区别:它评估表达式受影响的时候> currentBottle?.jiggle clos2 。因此,如果 currentBottle 当时 nil clos2 将是 nil ...即使 currentBottle 稍后获得非零值。


      As you (@matt) pointed out yourself, this other alternative has one other major difference: it evaluates currentBottle?.jiggle at the time that expression got affected to clos2. So if currentBottle is nil at that time, clos2 will be nil… even if currentBottle got a non-nil value later.

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

      Conversely, clos is affected to the closure itself, and the optional chaining is only evaluated each time clos is called, so it will evaluate to nil if currentBottle is nil… but will be evaluated to non-nil and will call jiggle() if we call clos() at a later time at which point currentBottle became non-nil.

      这篇关于Swift可选链接在关闭时不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆