【问题标题】:Swift Optional of Optional可选的 Swift 可选
【发布时间】:2015-04-28 13:07:13
【问题描述】:

对于我的一个项目,我必须创建一个代理 AppDelegate,它将调用转发到另一个 AppDelegate。

UIApplicationDelegate 有一个var window: UIWindow?。我的问题是,为什么我不能这样做:

private lazy var realAppDelegate: UIApplicationDelegate = {
    return AppDelegate()
}()

var window: UIWindow? {
    get {
        return realAppDelegate.window
    }
    set {
        realAppDelegate.window = newValue
    }
}

该代码的问题在于realAppDelegate.windowUIWindow??

有人知道为什么吗?

【问题讨论】:

标签: ios swift optional


【解决方案1】:

UIApplicationDelegate 协议的属性window 声明如下:

optional var window: UIWindow? { get set }

这意味着它是一个可选属性(在某种意义上,“实现UIApplicationDelegate 协议的类不需要实现/拥有这个属性”,就像你在 Objective-C 中有 @optional 时一样),并且该属性是可选类型 Optional<UIWindow>(或UIWindow?)。

这就是为什么最后会有双可选类型,因为window 属性可能会或可能不会在 realDelegate 中实现,如果是,它本身就是Optional<UIWindow>/UIWindow? 类型。


所以基本上你想要的是返回你的realAppDelegatewindow 属性......只有当realAppDelegate 决定声明该属性本身时(它不需要这样做,因为它是optional var) .

  • 如果realAppDelegate 本身没有实现window,您可能打算因此返回nil UIWindow?
  • 如果您的 realAppDelegate 确实实现了 window 属性,那么您需要按原样返回它(无论此实现返回实际的 UIWindow 还是 nil 之一)。

最简单的方法是在 Swift 中使用 nil-coalescing 运算符??a ?? b 表示“如果 a 非 nil,则返回 a,但如果 a 为 nil,则返回 b”(如果 a 的类型为 T?,则整个表达式应返回输入T,在你的例子中TUIWindow?)。

var window: UIWindow? {
    get {
        // If realAppDelegate.window (of type UIWindow??) is not implemented
        // then return nil. Otherwise, return its value (of type UIWindow?)
        return realAppDelegate.window ?? nil
        // That code is equivalent (but more concise) to this kind of code:
        //   if let w = realAppDelegate.window { return w } else return nil
    }
    ...
}

要实现setter,这是另一个问题。根据this SO answer,直接访问协议的可选属性的设置器似乎是不可能的。但是你可以想象一个解决这个问题的方法,通过声明另一个协议,使这个 window 属性要求是强制性的,然后尝试在 setter 中强制转换它:

@objc protocol UIApplicationDelegateWithWindow : UIApplicationDelegate {
    var window: UIWindow? { get set }
}

class AppDelegateWrapper : UIApplicationDelegate {
    ...
    var window: UIWindow? {
        get {
            return realAppDelegate.window ?? nil
        }
        set {
            if let realAppDelWithWindow = realAppDelegate as? UIApplicationDelegateWithWindow
            {
                // Cast succeeded, so the 'window' property exists and is now accessible
                realAppDelWithWindow.window = newValue
            }
        }
    }
...
}

【讨论】:

  • 您能否扩展您的答案以展示您将如何实施set { … }
  • 这实际上是一个非常好的问题......我担心这在 Swift 中是不可能的(但是?)根据stackoverflow.com/questions/26083377/… :-/
  • @AaronBrager 我更新了我的答案,提出了关于如何解决和实施它的建议。在操场上快速测试,似乎按预期工作。
  • 我没有测试过,但我想在我创建的UIApplicationDelegateWithWindow 协议中我只能请求实现{ set }(无需在getter 上添加不需要的约束)
【解决方案2】:

属性的声明是

optional var window: UIWindow? { get set }

开头的optional 表示该属性根本不必存在,即第二个?

UIApplicationDelegate 是一个协议,实现它的类不必实现所有东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-26
    • 2020-12-07
    相关资源
    最近更新 更多