##バージョン
・Xcode12.5.1
・Swift5
・iOS 14.5
##概要
コードでNavigationControllerを生成時、エラーは出ないがNavigationControllerが生成されなかった場合の対応について
iOS13以降でアプリの起動シーケンスが変わったのでハマったと考えらる。
##解決前のコード
AppDelegate.swiftでNavigationControllerの生成を実装
import UIKit
import CoreData
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
//
var window: UIWindow?
var navigationController: UINavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// 以下navigationControllerを生成するコード
let viewController: ViewController = ViewController()
navigationController = UINavigationController(rootViewController: viewController)
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
return true
}
}
##実行結果
![スクリーンショット 2021-07-09 20.39.55.png]
(https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423922/3eb07141-0c8e-43dc-1c43-1388604770da.png)
※赤枠の部分からviewを階層的に見てデバッグ
上図からNavigationControllerが生成されていないことがわかる
##対処法
・iOS12以前の場合
①SceneDelegate.swiftに@available(iOS 13.0, *)を追記する
import UIKit
// 追記部分
@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
}
~以下略~
}
②AppDelegate.swiftに@available(iOS 13.0, *)等を追記する
import UIKit
import CoreData
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// 以下2行を追加
var window: UIWindow?
var navigationController: UINavigationController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// 以下UINavigationController生成の実装部分
let viewController: ViewController = ViewController()
navigationController = UINavigationController(rootViewController: viewController)
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
return true
}
// @available(iOS 13.0, *)を追記する
@available(iOS 13.0, *)
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
@available(iOS 13.0, *)
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
・iOS13以降の場合
③SceneDelegateにUINavigationController生成のコードを実装する
import UIKit
@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
// UINavigationController型の変数を宣言
var navigationController: UINavigationController?
@available(iOS 13.0, *)
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
// // 以下UINavigationController生成の実装部分
let viewController: UIViewController = SampleViewController()
navigationController = UINavigationController(rootViewController: viewController)
self.window = UIWindow(windowScene: scene as! UIWindowScene)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
}
~以下略~
}
UINavigationControllerの生成が確認できる
##参考にさせて頂いた記事
storyboardを使わず、Swiftでナビゲーションバーをつくる(UINavigationControllerとか)
[iOS13のSceneDelegate周りのアプリの起動シーケンス]
(https://qiita.com/omochimetaru/items/31df103ef98a9d84ae6b)
[Storyboardを使わないiOSアプリ開発]
(https://zenn.dev/kazumalab/articles/76ca59f82c189cf33d43)
##終わりに
同じようなことで困ってる人の役に立ったら幸いです!
もし間違っている部分がありましたら、ご指摘いただけると嬉しいです!