为什么 double 类型的 main window 是可选的?

Why is main window of type double optional?

当访问 UIapplication's main window 时,它作为 UIWindow??

返回
let view = UIApplication.sharedApplication().delegate?.window // view:UIWindow??

为什么它作为双精度返回,它是什么意思,如果放入 if let 我应该在它后面添加一个 ! 吗?

if let view = UIApplication.sharedApplication().delegate?.window!

我的第一个想法是在委托后用 ! 替换 ?,但这不是解决方案。

因为window 属性本身有疑问(可选)。因此,您需要一个问号,因为可能有也可能没有 window 属性,而另一个问号是因为 window 属性 的 return 值本身是可选的。因此我们得到了一个双重包装的 Optional(正如我在 tutorial 中解释的那样:向下滚动到提示框,我在其中讨论当一个可选的 属性 具有一个 Optional 值时会发生什么)。

因此,表达这一点的一种方式是分为两个阶段——一个是转换(并展开 that 可选),另一个是获取 window(和展开 that 可选):

if let del = UIApplication.sharedApplication().delegate as? AppDelegate {
    if let view = del.window {

现在 view 是一个 UIWindow。

当然,如果您确定自己的立场(您可能确实如此),则可以强制在第一行强制转换并在第二行强制展开。所以,在 Swift 1.2:

let del = UIApplication.sharedApplication().delegate as! AppDelegate
let view = del.window!

@matt 有详细信息,但有一个(有点可怕,有点棒)解决方法。 (不过请参阅下面的编辑)

let window = app.delegate?.window??.`self`()

我将把对这行代码的理解留作reader的练习。

好吧,我说谎,我们分解一下。

app.delegate?.window

好的,到目前为止一切顺利。在这一点上,我们遇到了让我们头疼的 UIWindow??(我相信是 Swift 中的一个 错误 Swift 和 Cocoa).我们想折叠它两次。我们可以使用可选链接 (?.) 来做到这一点,但它会展开和重新包装,所以我们回到了起点。但是,您可以使用 ??. 双可选链,这很奇怪,但是有效。

很好,但是 ?? 不是合法的后缀运算符。您实际上必须链接到某些东西。好吧,我们想链接回它自己(即 "identity")。 NSObject 协议给了我们一个标识方法:self.

selfNSObject 上的方法,但它也是 Swift 中的保留字,所以它的语法是 `self`()

所以我们得到了我们的疯狂。随心所欲地使用它。

请注意,由于 ??. 有效,因此从技术上讲您不需要它。您可以只接受 viewUIWindow?? 并像 view??.frame 一样在其上使用 ??.。它有点吵,但可能不会对少数需要它的地方造成任何实际问题。

(*) 我曾经认为这是 Swift 中的错误,但它不能通过可选链接直接修复。问题是没有可选的链接过去 window。所以我不确定修复它的正确位置在哪里。 Swift 可以允许后缀-? 表示 "flatten" 而无需链接,但这感觉很奇怪。我想正确的运算符应该是 interrobang delegate?.window‽ :D 我相信这不会引起任何混淆。

编辑:

Joseph Lord pointed out the better solution(这与我一直用来避免琐碎的 if-let 的技术非常相似,但之前没有想到过这种方式):

let window = app.delegate?.window ?? nil // UIWindow?

我同意他的看法,这是正确的答案。

对于我来说,随着 Swift2 的出现,在这种情况下通常的解决方法是

if let _window = UIApplication.sharedApplication().delegate?.window, window = _window {
    // Some code... i.e.
    let frame = window.frame
}

双选哦!有时您可以使用 double-bang(两个感叹号),但您不能使用可选绑定那样进行转换。所以...我对所有其他代码的混音为您提供了一个名为 window 的 non-optional 类型的 UIWindow 对象:

guard let w = UIApplication.shared.delegate?.window, let window = w else { return }

但我们不要浪费时间,直接使用

let window = UIApplication.shared.delegate!.window!!

完成。