コードでNavigationControllerを生成したときにハマったことと、解決策

##バージョン

・Xcode12.5.1
・Swift5
・iOS 14.5

##概要
コードでNavigationControllerを生成時、エラーは出ないがNavigationControllerが生成されなかった場合の対応について

iOS13以降でアプリの起動シーケンスが変わったのでハマったと考えらる。


##解決前のコード
AppDelegate.swiftでNavigationControllerの生成を実装

```swift:AppDelegate.swift
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, *)を追記する

```swift:SceneDelegate.swift
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, *)等を追記する

```swift:AppDelegate.swift
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生成のコードを実装する

```swift:SceneDelegate.swift
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()
        
    }
            ~以下略~
}


```

##解決策実行後の結果
![スクリーンショット 2021-07-09 20.36.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423922/0ef19165-812d-e9d8-260b-1730adec70ab.png)

UINavigationControllerの生成が確認できる

##参考にさせて頂いた記事
[storyboardを使わず、Swiftでナビゲーションバーをつくる（UINavigationControllerとか）](https://qiita.com/mochizukikotaro/items/f053495eb130e92e13e8)
[iOS13のSceneDelegate周りのアプリの起動シーケンス]
(https://qiita.com/omochimetaru/items/31df103ef98a9d84ae6b)
[Storyboardを使わないiOSアプリ開発]
(https://zenn.dev/kazumalab/articles/76ca59f82c189cf33d43)

##終わりに
同じようなことで困ってる人の役に立ったら幸いです！
もし間違っている部分がありましたら、ご指摘いただけると嬉しいです！