展开多个Swift选项

时间:2015-01-19 22:31:08

标签: cocoa swift

我正在尝试用Swift重写部分ObjC代码,很多cocoa对象属性在Swift中返回可选值。是否有更好的模式而不是这种深度嵌套:

  if let panel = self.window {
     if let screens = NSScreen.screens() {
        if  let screenRect = screens[0].frame {
           let statusRect = CGRectZero
              ...

5 个答案:

答案 0 :(得分:2)

虽然莱昂纳多的答案很好,但除非你知道对象是非可选的,否则会导致异常,这是一个更好的模式,应该被视为伪代码:

if let frame = NSScreen.screens()?.first?.frame {
   // Do something with frame.
}

换句话说,使用可选链接(?.),但只使用链接最后一部分的let

如果你想链接不同类型的选项,你也可以创建这样的运算符,其中只返回最后一个的值:

infix operator ??? { associativity left }

func ??? <T1, T2>(t1: T1?, t2: @autoclosure () -> T2?) -> T2? {
    return t1 == nil ? nil : t2()
}

if let frame = self.window ??? NSScreen.screens()?.first?.frame {
    // Do something with frame
}

当然,这是受到Haskell绑定的启发。但就像这样有趣,我不推荐它。我认为这很明显是泥巴。 (顺便说一下,?????之间的差异是前者要求lhs和rhs属于同一类型(或超类型),而后者确实。???总是返回其rhs或nil。)

答案 1 :(得分:1)

你可以像这样强行打开它:

NSScreen.screens()!.first!.frame!
NSScreen.screens()!.first!.frame!.width
NSScreen.screens()!.first!.frame!.height


// safely unwraping it as required an mentioned by Gregory
if let frame = NSScreen.screens()?.first?.frame {
    println(frame)
}
if let width = NSScreen.screens()?.first?.frame?.width {
    println(width)
}
if let height = NSScreen.screens()?.first?.frame?.height {
    println(height)
}

答案 2 :(得分:1)

wrote a blog post前一段时间探索了几种不同的解包方式。

您可以创建一个可以一次解包多个选项的函数:

func if_let<T, U, V>(a: Optional<T>, b: Optional<U>,
  c: Optional<V>, fn: (T, U, V) -> ()) {
  if let a = a {
    if let b = b {
      if let c = c {
        fn(a, b, c)
      }
    }
  }
}

使用如下:

if_let(a, b, c) {
  a, b, c in
  println("\(a) - \(b) - \(c)")
}

有人还使用元组提出了一个简洁的解决方案,可以是found in this gist

答案 3 :(得分:0)

从Swift 1.2开始,您可以在一行中展开,如本答案中所述:

unwrapping multiple optionals in if statement

答案 4 :(得分:0)

请在此处阅读有关可选链接的信息: Linking Multiple Levels of Chaining

你可以在这个游乐场玩它看看它是如何运作的:

import UIKit


class AAA {
    var string: String? = nil
}

class AA {
    var aaa: [AAA?]? = nil
}

class A {
    var aa: AA? = nil
}


var a: A?

a = A()

/// Comment/Uncomment next lines
a?.aa = AA()
//a?.aa?.aaa = [AAA()]
a?.aa?.aaa = []
a?.aa?.aaa?.first??.string = "My String Value"

if let myString = a?.aa?.aaa?.first??.string {
    print("myString: \(myString)")
} else {
    print("myString does not acceptable")
}

您的代码可能如下所示:

if let panel = self.window, let statusRect = NSScreen.screens()?.first??.frame ?? CGRect.zero {
    /// your code to work with panel and statusRect
}
相关问题