7

I'm converting my iOS13 app for iPadOS to SceneDelegate (multi window).

How can I get the current UIWindow from the current SceneDelegate?

I know that a can access the current scene using UIView.window or UIViewController.view.window, but I have a non UI class (AppDelegate) where I need to get the window (keyWindow until iOS12) to show a snack bar on top of everything.

I used to do [UIApplication sharedApplication].keyWindow but now, of course, that's wrong.

Fabiosoft
  • 883
  • 12
  • 23

6 Answers6

8

Swift 5.x / iOS 13.x

Inspired by many solutions, to get back my old window property (searching it inside the connectedScenes) I've realized a little extension:

extension UIApplication {
    var currentWindow: UIWindow? {
        connectedScenes
        .filter({$0.activationState == .foregroundActive})
        .map({$0 as? UIWindowScene})
        .compactMap({$0})
        .first?.windows
        .filter({$0.isKeyWindow}).first
    }
}

Usage:

if let window = UIApplication.shared.currentWindow { 
   // do whatever you want with window
}
Alessandro Ornano
  • 31,579
  • 11
  • 90
  • 115
6

You'll want to simply iterate through all your windows and find the key window manually.

for (UIWindow *window in [UIApplication sharedApplication].windows) {
    if (window.isKeyWindow) {
        // you have the key window
        break;
    }
}

DO NOT use UISceneActivationStateForegroundActive as the check. That means something different and folks are introducing bugs by using logic to find the first UISceneActivationStateForegroundActive window scene.

NSProgrammer
  • 2,328
  • 1
  • 21
  • 27
1

It sounds like you probably want to move this logic to your SceneDelegate.

The SceneDelegate now has knowledge of whether the window is connected to the scene, so it might make sense to have every connected scene listen to whatever event is driving the snack bar, and the show it on its window. This would then result in every visible window showing the snack bar (1 or more).

Mark
  • 6,777
  • 3
  • 41
  • 63
1

You could try:

    if let window = UIApplication.shared.windows.first(where: { (window) -> Bool in window.isKeyWindow}) {
    //your code
    }

Hope this helps!

0

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

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

    UIWindow* window = nil;
    if (@available(iOS 13.0, *))
    {
        for (UIWindowScene* wScene in [UIApplication sharedApplication].connectedScenes)
        {
            if (wScene.activationState == UISceneActivationStateForegroundActive)
            {
                window = wScene.windows.firstObject;

                break;
            }
        }
    }
  • this is incorrect. That is not what `UISceneActivationStateForegroundActive` means. You want `window.isKeyWindow` – NSProgrammer Sep 17 '19 at 16:22
  • The question is "What is the way to get UIWindow from non-UI class. On the other hand, the key window is: "The key window receives keyboard and other non-touch related events. Only one window at a time may be the key window." You can have more than one active windows that are touch-able at the same time on the screen and only one of them is keyWindow, but it might not be the wanted window. There is no absolutely correct answer to this question, that is why my solution is a proposal in one concrete scenario. – Iliyan Kafedzhiev Sep 17 '19 at 17:49
  • And that is why Apple deprecated, keyWindow property from UIApplication. – Iliyan Kafedzhiev Sep 17 '19 at 17:59
  • 1
    I see what you were getting at. I suppose in a world of rapid stack overflow copying and pasting I wanted to interject to avoid folks misunderstanding and applying code that will lead to bugs (as my developer did copying this code to our code base). I apologize for pushing that your intent was wrong, that was unfair. – NSProgrammer Sep 17 '19 at 22:00
-1

I haven't tried this yet, but you should be able to get all the windows with [UIApplication sharedApplication].windows and then pick if you want to show the snack bar on all of the windows or one window.

Gabe
  • 2,201
  • 1
  • 22
  • 17