我正在尝试用Swift重写部分ObjC代码,很多cocoa对象属性在Swift中返回可选值。是否有更好的模式而不是这种深度嵌套:
if let panel = self.window {
if let screens = NSScreen.screens() {
if let screenRect = screens[0].frame {
let statusRect = CGRectZero
...
答案 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开始,您可以在一行中展开,如本答案中所述:
答案 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
}