3

when updating my App's Deployment target to 15.0, i receive this warning:

'windows' was deprecated in iOS 15.0: Use UIWindowScene.windows on a relevant window scene instead

I have tried to look on the net what could be done to remediate this, but couldn't find much info on this. Hope you could share some advice.

The line of code i am using where this alert occurred is:

let window = UIApplication.shared.windows[0]

followed by in my ViewDidLoad():

 DispatchQueue.main.async { [weak self] in
        if defaults.bool(forKey: "darkModeBoolSwitch") == true {
            self?.window.overrideUserInterfaceStyle  = .dark
            
        } else if defaults.bool(forKey: "darkModeBoolSwitch") == false {
            self?.window.overrideUserInterfaceStyle  = .light
            
        }
Daniel C
  • 113
  • 1
  • 8

3 Answers3

5

An alternative to @DuncanC's solution that may also work for you: UIApplication has a connectedScenes property, which lists all of the currently-active scenes doing work in your application (for most applications, this is just the one main scene).

Of those scenes, you can filter for scenes which are UIWindowScenes (ignoring scenes which are not currently active and in the foreground), and of those, find the first scene which has a window which is key:

extension UIApplication {
    static var firstKeyWindowForConnectedScenes: UIWindow? {
        UIApplication.shared
            // Of all connected scenes...
            .connectedScenes.lazy

            // ... grab all foreground active window scenes ...
            .compactMap { $0.activationState == .foregroundActive ? ($0 as? UIWindowScene) : nil }

            // ... finding the first one which has a key window ...
            .first(where: { $0.keyWindow != nil })?

            // ... and return that window.
            .keyWindow
    }
}

I hesitate to call this extension something like UIApplication.keyWindow because the reason for the deprecation of these APIs is because of the generalization to multi-scene applications, each of which may have its own key window... But this should work.

If you still need to support iOS 14, which does not have UIWindowScene.keyWindow, you can replace the firstWhere(...)?.keyWindow with: flatMap(\.windows).first(where: \.isKeyWindow).

Itai Ferber
  • 28,308
  • 5
  • 77
  • 83
0

I am out-of-date with Apple's recent changes to implement scenes.

I did a little digging, and found a protocol UIWindowSceneDelegate

It looks like you are supposed to add an "Application Scene Manifest" to your app's info.plist file that tells the system the class that serves as the app's window scene delegate.

Then in that class you want to implement the method scene(_:willConnectTo:options:). When that method is called you sould try to cast the UIScene that's passed to you to to a UIWindowScene, and if that cast succeeds, you can ask the window scene for it's window and save it to an instance property.

That should allow you to save a pointer to your app's window and use it when needed.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
0

After lot of research, following is what worked for me -

UIWindow *firstWindow = nil;
NSSet *scenes = [[UIApplication sharedApplication] connectedScenes];
NSArray *windows = nil;
for (id aScene in scenes) {
  if ([aScene activationState] == UISceneActivationStateForegroundActive) {
    windows = [aScene windows];
    break;
  }
}

for (UIWindow *window in windows) {
  if (window.isKeyWindow) {
    firstWindow = window;
    break;
  }
}
Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • You should move the `windows=[aScene windows];` line inside the `if([aScene activationState]==UISceneActivationStateForegroundActive)` block (be sure you add curly braces to include the moved line and the `break`. – HangarRash Apr 04 '23 at 21:05
  • Hi @HangarRash, Tried your suggestion and it crashes. This is what I tried - UIWindow *firstWindow = nil; NSSet *scenes=[[UIApplication sharedApplication] connectedScenes]; NSArray *windows; for(id aScene in scenes){ //can't use the first object if([aScene activationState]==UISceneActivationStateForegroundActive){ windows=[aScene windows]; break; } } for (UIWindow *window in windows) { if (window.isKeyWindow) { firstWindow = window; break; } } – user1664018 Apr 06 '23 at 02:21
  • 1
    You forgot the `windows=[aScene windows];` line. And I suggest you initialize `windows` to `nil`. – HangarRash Apr 06 '23 at 02:24
  • initializing windows did the trick. Thank you @HangarRash. – user1664018 Apr 06 '23 at 02:35