Swift可选可选

del*_*oyk 3 optional ios swift

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

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

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

var window: UIWindow? {
    get {
        return realAppDelegate.window
    }
    set {
        realAppDelegate.window = newValue
    }
}
Run Code Online (Sandbox Code Playgroud)

该代码的问题realAppDelegate.window是a UIWindow??.

有人知道为什么吗?

Ali*_*are 7

该物业windowUIApplicationDelegate协议,声明如下:

optional var window: UIWindow? { get set }
Run Code Online (Sandbox Code Playgroud)

这意味着它是一个可选属性(在某种意义上说"实现UIApplicationDelegate协议的类不被请求实现/具有此属性 ",就像 @optional在Objective-C中一样),并且该属性是可选类型 Optional<UIWindow>(或UIWindow?) .

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


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

  • 如果realAppDelegate没有实现window自己,你可能打算返回nil UIWindow?一个结果.
  • 如果你realAppDelegate确实实现了window属性,那么你需要按原样返回它(这个实现返回一个实际的UIWindownil一个).

最简单的方法是??在Swift中使用nil-coalescing运算符.a ?? b意思是"如果a是非nil,则返回a,但如果a为nil,则返回b"(如果a是类型的话T?,那么整个表达式应该返回一个类型的对象T,在你的情况下T是类型UIWindow?).

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
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

要实现setter,这是另一个问题.根据这个SO答案,似乎不可能直接访问协议的可选属性的setter.但你可以想象一个黑客来解决这个问题,通过声明另一个使这个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
            }
        }
    }
...
}
Run Code Online (Sandbox Code Playgroud)