Custom UIWindow subclass with UIWindowScene

I'm trying to support Scenes in my app. One library that I use has a UIWindow subclass for triggering debug gestures anywhere in the app. In my pre-Scenes app I had code like this to sometimes use that subclass:


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    ...
    
    let window: UIWindow
    if ScribbleTweaks.enabled {
        window = TweakWindow(frame: UIScreen.main.bounds, gestureType: .shake, tweakStore: ScribbleTweaks.defaultStore)
    } else {
        window = UIWindow(frame: UIScreen.main.bounds)
    }


    window.rootViewController = navController
    window.makeKeyAndVisible()
    
    ...
}

Is there any way to do something similar with a UIWindowSceneDelegate? I can't find any API for configuring the UIWindow class.


As a follow-up, is it possible to use UIWindowScene without storyboards? Currently I don't use storyboards and it would be nice to port over the same code for configuring the initial view controllers.

Accepted Reply

Roughly (not my actual code):


In your AppDelegate:

- (UISceneConfiguration *)application:(UIApplication *)application

configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession

options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0)) {

let configuration = [UISceneConfiguration configurationWithName:@"MyOrdinaryDefaultMainSceneConfiguration"

sessionRole:UIWindowSceneSessionRoleApplication];

configuration.sceneClass = UIWindowScene.class;

configuration.delegateClass = MySceneDelegate.class;

// configuration.storyboard = nope don't set this.

return configuration;

}


In your MySceneDelegate (subclass of NSObject is fine, implements UIWindowScene protocol):


@synthesize window = _window;

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {

self.window = [[TweakWindow alloc] initWithWindowScene:(UIWindowScene*)scene andThoseOtherParametersYouMightHaveToSubclassTweakWindowToArrangeThis];

self.window.rootViewController = navController;

[self.window makeKeyAndVisible];

}

Replies

Roughly (not my actual code):


In your AppDelegate:

- (UISceneConfiguration *)application:(UIApplication *)application

configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession

options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0)) {

let configuration = [UISceneConfiguration configurationWithName:@"MyOrdinaryDefaultMainSceneConfiguration"

sessionRole:UIWindowSceneSessionRoleApplication];

configuration.sceneClass = UIWindowScene.class;

configuration.delegateClass = MySceneDelegate.class;

// configuration.storyboard = nope don't set this.

return configuration;

}


In your MySceneDelegate (subclass of NSObject is fine, implements UIWindowScene protocol):


@synthesize window = _window;

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {

self.window = [[TweakWindow alloc] initWithWindowScene:(UIWindowScene*)scene andThoseOtherParametersYouMightHaveToSubclassTweakWindowToArrangeThis];

self.window.rootViewController = navController;

[self.window makeKeyAndVisible];

}

There is another trick you can use.

First you make a dummy class that conforms to UIWindowSceneDelegate:

Code Block swift
open class MyWindowSceneDelegate: NSObject & UIWindowSceneDelegate {}


Since all the requirements of UIWindowSceneDelegate are optional, the compiler will be happy. Afterwards you can do this:

Code Block swift
open class MyRealWindowSceneDelegate: MyWindowSceneDelegate {
@objc var window: MyCustomUIWindowSubclass
}


At runtime when window is resolved, it will be of type MyCustomUIWindowSubclass.