15

I was reading Apple docs, when I found this sentence:

The AppDelegate class contains a single property: window.

var window: UIWindow?

This property stores a reference to the app’s window. This window represents the root of your app’s view hierarchy. It is where all of your app content is drawn. Note that the window property is an optional, which means it may have no value (be nil) at some point.

What I don't understand is: why this property at some point could be nil? What's the case for it to be(come) nil?

Community
  • 1
  • 1

3 Answers3

16

When you close your application, your app can still receive silentNotifications or download data in the background, track your location, play music, etc.

In the images below, the encircled red are for when your app is still doing something, however it is no longer on the screen. It's in the background, so AppDelegate doesn't need a window anymore. As a result it will be set to nil

Simple overview

enter image description here


Detail overview

enter image description here

FWIW, the code below won't make the app launch with vc.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        let vc = ViewController()
        window?.rootViewController = vc
        window?.makeKeyAndVisible()
        return true
    }

Why it doesn't work? Because the window property is an optional—initially set to nil.It needs to be instantiated

The code below will work

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    let vc = ViewController()
    window = UIWindow(frame: UIScreen.main.bounds) // Now it is instantiated!!
    window?.rootViewController = vc
    window?.makeKeyAndVisible()
    return true
}
Honey
  • 24,125
  • 14
  • 123
  • 212
5

You may not always need it. For example, when these two methods are called :

application(_:performFetchWithCompletionHandler:)
application(_:handleEventsForBackgroundURLSession:completionHandler:)

your app will not be shown to the user, so there is no need for a window.

As always, more in the docs

Now, I'm not sure that this is the inherent reason, but it seems as a good enough possibility (at least for me). Though if someone is able to provided some more information, I'd gladly learn some more also.

Losiowaty
  • 7,548
  • 2
  • 30
  • 45
  • Thanks for your kind reply. What it feels strange is the fact that, the way it is described, it looks like there's always a window but at some point, under certain circumstances, it could be nil. This surprises me a little, since that window should be a sort of root, the first place your app uses to draw its contents (even if your app performs background actions, I suppose) –  Dec 08 '15 at 15:25
  • 1
    Well, these methods in particular are called when your app is inactive - i.e. the user is not using it at the moment - he may be using another app or not even using his phone at the moment. Then, there is no need to use more resources than needed - especially with the fact that you have limited processing time to finish your work (~30 seconds). – Losiowaty Dec 08 '15 at 15:32
  • is there any way to test, when these methods are called, if window is nil? –  Dec 08 '15 at 15:34
  • 1
    Well, logging to console may be a problem :) I suppose you could write a value to `NSUserDefaults` when `window == nil` and then when running the app simply retrieve the value and either log it in console or in a label. – Losiowaty Dec 08 '15 at 15:37
4

It becomes more obvious when you create the window programmatically instead of using a main storyboard, which automatically sets the window property.

You may not want to or not be able to create the window immediately when your delegate object (AppDelegate in your case) is created. Usually you don't need to create the window and set the property until application(_:didFinishLaunchingWithOptions:) was called. So until the window is created and the property is set it will be nil.
Like Losiowaty already stated this is also the case when the app is started but not displayed to the user - e.g. when just processing location updates or other information in the background.

If the property would be non-optional then you would be forced to create the window at the moment you create your AppDelegate object which is neither desired nor necessary.

Community
  • 1
  • 1
fluidsonic
  • 4,397
  • 1
  • 21
  • 34
  • That's an excellent point! I guess, I never though about `AppDelegate` having a normal object lifecycle - i.e. that there is an `init` somewhere before `application(_:didFinishLaunchingWithOptions:)`, as it was usually considered an "entry point" to it. – Losiowaty Dec 09 '15 at 08:32