23

I am using Xcode 11 (beta3) and building an app for iOS 13. In my project I created the delegate methods for UIWindowSceneDelegate declaring it in Info.plist. Now I'm able to create multiple windows (and UIScene).

How can I access the rootViewController now I've not anymore a single window? I need it to get some reference to objects and bounds it holds.

In my AppDelegate window is nil, and in my ViewController (child view controller) instance I tried using self.view.window.rootViewController but I found out that viewDidLoad() is too soon (I think) and the window is still nil, works in viewDidAppear(), but I don't need to make this process every time the view controller appears.

What's the best practice with this new way to handle application scenes?

Here is my AppDelegate:

func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        return true
    }

    func application(_ application: UIApplication,
                     configurationForConnecting connectingSceneSession: UISceneSession,
                     options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

My SceneDelegate:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // yes it's empty, I'm using storyboard
    }
Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
Fabiosoft
  • 1,141
  • 14
  • 32

2 Answers2

24

Now you have more than one rootViewController, one for each scene. First, you have to answer which one you need at the moment of usage.

Probably you want to get one of the rootViewController of the currently active scene then you can use this:

        var rootVC:UIViewController? = nil
        if #available(iOS 13.0, *) {
            for scene in UIApplication.shared.connectedScenes {
                if scene.activationState == .foregroundActive {
                    rootVC = ((scene as? UIWindowScene)!.delegate as! UIWindowSceneDelegate).window!!.rootViewController
                    break
                }
            }
        } else {
            // Fallback on earlier versions
        }
11

You can access connected scenes using:

UIApplication.shared.connectedScenes

As per Apple documentation:

Connected scenes are those that are in memory and potentially doing active work. A connected scene may be in the foreground or background, and it may be onscreen or offscreen.

Then you can iterate through them and try to get UIWindowScene from there.

guard let windowScene = (scene as? UIWindowScene) else { return }
print(windowScene.windows) // This will print windows associated with the scene.

On the other hand, from the view controller you can access the window through the view:

self.view.window
Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
P_O
  • 435
  • 6
  • 16
  • `windowScene` has value only on current scene? – Fabiosoft Jul 17 '19 at 10:36
  • 1
    [This document on page 39](https://devstreaming-cdn.apple.com/videos/wwdc/2019/212nyxqyrke8a9t/212/212_introducing_multiple_windows_on_ipad.pdf?dl=1) says there might be a few UIWindows in the same scene. – P_O Jul 17 '19 at 23:39
  • 1
    I can't believe they broke everything... now what's the top window and how can I add a UIView that stays on top of everything? – Fabiosoft Jul 18 '19 at 07:20
  • 1
    I have update the answer. Meanwhile, I wouldn't say there is a top window. There might be Foreground Active or Foreground Inactive windows. Have a look [WWDC session](https://developer.apple.com/videos/play/wwdc2019/212). It covers principals behind the multi window UI. I hope you will find it useful. – P_O Jul 19 '19 at 06:11