Xcode11とUISceneとUIWindowにまつわるトラブルシュートに追われている。
個別のケースに分解してお届け。
現象
- Xcode11で作成したプロジェクトをiOS13で実行しているとき、UIWindowが表示されない
- rootViewController持たせて、
viewDidLoad
にbreak pointを貼ったりすると、動作はしていることが確認できる。
原因
- Xcode11で作る新規プロジェクトは、Scene Based Lifecycleが有効になっている。
- Scene Based Lifecycleが有効になっていると、
[UIWindow new]
,[[UIWindow alloc] initWithFrame:]
で生成したwindowは View Hierarchyに載らなくなる- UIWindowを載せるべきWindowSceneが不明なため
対応
ひとつは、Xcode11で作成したプロジェクトからSceneに関する機能をオミットする方法。
もうひとつは正攻法。(本記事)
[[UIWindow alloc] initWithWindowScene:]
で windowを生成する。
そのためには、なんらかの手段によってUIWindowScene
を拾い上げる必要がある。
ボタンを押した時に表示したいとか、特定のViewと同じUIWindowSceneを選択する場合
ViewController.m
@interface ViewController ()
@property (nonatomic) UIWindow *window;
@end
@implementation ViewController
- (IBAction)openWindow:(UIButton *)sender {
UIWindowScene *scene = sender.window.windowScene;
UIWindow *window = [[UIWindow alloc] initWithWindowScene: scene];
// 以下は確認用の見た目調整と表示
UIViewController *viewController = [UIViewController new];
viewController.view.backgroundColor = UIColer.greenColer;
window.frame = CGRectMake(20, 20, 50, 50);
window.rootViewContoller = viewController;
self.window = window;
[self.window makeKeyAndVisible];
}
@end
ViewController.swift
class ViewController: UIViewController {
var window: UIWindow?
@IBAction func openWindow(_ sender: UIButton) {
guard let scene = sender.window?.windowScene { return }
let window = UIWindow(windowScene: scene)
// 以下は確認用の見た目調整と表示
let viewController = UIViewController()
viewController.view.backgroundColer = .green
window.frame = CGRect(x:20, y:20, width:50, height:50)
window.rootViewContoller = viewController
self.window = window
self.window?.makeKeyAndVisible();
}
}
Sceneは一つだけのアプリである場合など、UIApplicationからUIWindowSceneを引っ張りたい場合
ViewController.m
@interface ViewController ()
@property (nonatomic) UIWindow *window;
@end
@implementation ViewController
- (IBAction)openWindow:(UIButton *)sender {
UIWindowScene *scene = (UIWindowScene*)[[[[UIApplication sharedApplication] connectedScenes] allObjects] first];
UIWindow *window = [[UIWindow alloc] initWithWindowScene: scene];
// 以下は確認用の見た目調整と表示
UIViewController *viewController = [UIViewController new];
viewController.view.backgroundColor = UIColer.greenColer;
window.frame = CGRectMake(20, 20, 50, 50);
window.rootViewContoller = viewController;
self.window = window;
[self.window makeKeyAndVisible];
}
@end
ViewController.swift
class ViewController: UIViewController {
var window: UIWindow?
@IBAction func openWindow(_ sender: UIButton) {
guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene { return }
let window = UIWindow(windowScene: scene)
// 以下は確認用の見た目調整と表示
let viewController = UIViewController()
viewController.view.backgroundColer = .green
window.frame = CGRect(x:20, y:20, width:50, height:50)
window.rootViewContoller = viewController
self.window = window
self.window?.makeKeyAndVisible();
}
}