For a project of mine, I have to create a proxy AppDelegate that will forward calls to a another AppDelegate.
UIApplicationDelegate havs a var window: UIWindow?
. My question is, why can't I do this:
private lazy var realAppDelegate: UIApplicationDelegate = {
return AppDelegate()
}()
var window: UIWindow? {
get {
return realAppDelegate.window
}
set {
realAppDelegate.window = newValue
}
}
The problem with that code is that realAppDelegate.window
is a UIWindow??
.
Does anybody know why?
The property window
of UIApplicationDelegate
protocol is declared like this:
optional var window: UIWindow? { get set }
That means that it is an optional property (in the sense that "the class implementing the UIApplicationDelegate
protocol is not requested to implement/have this property", like when you have @optional
in Objective-C), and that property is of optional type Optional<UIWindow>
(or UIWindow?
).
That's why you have the double-optional type in the end, because that window
property may or may not be implemented in realDelegate, and if it is, it will be itself of type Optional<UIWindow>
/UIWindow?
.
So basically what you want is to return the window
property of your realAppDelegate
… only if that realAppDelegate
decided to declare that property itself (which it isn't requires to do, as it's optional var
).
realAppDelegate
did not implement window
itself, you probably intend to return a nil
UIWindow?
as a result.realAppDelegate
did actually implement the window
property, then you need to return it as is (wether this implementation returns an actual UIWindow
or a nil
one).The easiest way to do that is to use the nil-coalescing operator ??
in Swift. a ?? b
meaning that "if a is non-nil, then return a, but if a is nil, return b" (where if a
is of type T?
, then the whole expression is expected to return an object of type T
, where in your case T
is the type 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
}
...
}
To implement the setter, that's another problem. According to this SO answer, directly accessing to the setter of an optional property of a protocol doesn't seem to be possible. But you can imagine a hack to workaround this, by declaring another protocol that makes this window
property requirement mandatory, then try to cast to it in the 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
}
}
}
...
}
The declaration of the property is
optional var window: UIWindow? { get set }
The optional
in the beginning means that the property doesn't have to be there at all, that's the second ?
.
UIApplicationDelegate
is a protocol, the class that implements it doesn't have to implement everything.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With