Search code examples
objective-cswiftappdelegateuiwindow

Unwrap UIWindow twice from AppDelegate in Swift


To Get the rootViewController in Objective-c you can use the below line of code

[[[UIApplication sharedApplication] delegate] window].rootViewController

I tried to do the same in swift

UIApplication.sharedApplication().delegate?.window?.rootViewController

But I got this error

'UIWindow?' does not have a member named 'rootViewController'

And the suggestion says that you have to unwrap UIWindow twice UIWindow?? to be

UIApplication.sharedApplication().delegate?.window??.rootViewController

My Question is: Why do I need to unwrap the window twice ?

.

.


I have looked in the API and found that

protocol UIApplicationDelegate : NSObjectProtocol {
    optional var window: UIWindow? { get set }
}

The window has one optional

class UIWindow : UIView {
    var rootViewController: UIViewController?
}

Also the rootViewController has one optional

.

.


I thought may be because UIWindow in UIApplicationDelegate protocol has optional and UIWindow? so I tried the below in Playground

@objc protocol MyApplicationDelegate {
    optional var myWindow: MyWindow? { get set }
}

class MyWindow : NSObject {
    var rootViewController: Int?
    init(number: Int) {
        rootViewController = number
    }
}

class MyAppDelegate: MyApplicationDelegate {
    var myWindow: MyWindow?
    init() {
        myWindow = MyWindow(number: 5)
    }
}

let myDelegate = MyAppDelegate()
println(myDelegate.myWindow?.rootViewController)

However I can get myWindow with one optional and can successfully log '5'

What am I missing here?


Solution

  • Well; I found the problem with my example

    In my example I'm creating object from MyAppDelegate directly which will sure have myWindow property as I'm defining it

    Changing the example to be the following

    @objc protocol MyApplicationDelegate {
        optional var myWindow: MyWindow? { get set }
    }
    
    class MyWindow : NSObject {
        var rootViewController: Int?
        init(number: Int) {
            rootViewController = number
        }
    }
    
    class MyAppDelegate: MyApplicationDelegate {
        var myWindow: MyWindow?
        init() {
            myWindow = MyWindow(number: 5)
        }
    }
    
    class MyApplication: NSObject {
        var myDelegate: MyApplicationDelegate
        override init() {
            myDelegate = MyAppDelegate()
        }
    }
    
    let myApplication = MyApplication()
    println(myApplication.myDelegate.myWindow??.rootViewController)
    

    I needed to add another class MyApplication that has a property conform toMyApplicationDelegate

    So I was able to use myWindow?? first unwrapping for the optional part in the protocol and second one is for the optional declaration in the variable UIWindow?