【Swift】Main.storyboardを利用しない場合に注意しなければならない設定

Main.storyboardを使わない場合、各種設定を変更しないとMain.storyboardが見つからないよというエラーが生じる。初心者にはこの辺りの設定が理解できておらずエラーに対処してもわからなさが残るため、いくつかポイントとなる部分だけまとめています。

#AppDelegate

通常、新規にプロジェクトを立ち上げた際には、AppDelegate.swiftには次のようにAppDelegateクラスが記述されている。AppDelegate内に直接Main.storyboardの記述がなされているわけでないが、SceneDelegateの絡みで削除しておくべき箇所がある。

```swift
import UIKit

@main //エントリーポイントとなるattributes:属性
class AppDelegate: UIResponder, UIApplicationDelegate {
      //UIResponderはクラス
      //UIApplicationDelegateはプロトコル　　　　　　　　　　

    // アプリの起動時に呼ばれる
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // アプリケーションの起動後にカスタマイズするためのオーバーライドポイントです。
        return true
    }

    // MARK: UISceneSession Lifecycle
    
    // シーンの起動時に呼ばれる
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // 新しいシーンセッションが作成されるときに呼び出されます。
        // このメソッドを使用して、新しいシーンを作成するための構成を選択します。
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
        //SceneConfigurationはinitialViewを指定する
        //設定はinfo.plistにあり、初期状態では"Default Configuration"　(＝Main.storyboard)
    }

    // シーンの終了時に呼ばれる
    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // ユーザーがシーンセッションを破棄したときに呼び出されます。
        // アプリケーションが実行されていないときにセッションが破棄された場合は、application:didFinishLaunchingWithOptionsの直後にこれが呼ばれます。
        // 廃棄されたシーンに固有のリソースは戻らないので、このメソッドを使って解放してください。
    }


}
```


##application(_:didFinishLaunchingWithOptions:)
Tells the delegate that the launch process is almost done and the app is almost ready to run.

と書いてあるように、一番はじめのメソッドは起動のプロセスがほぼ終了しているもしくはアプリを走らせるのがほぼ準備できていることをデリゲートに伝える。ここまではいいのだけど、他のメソッドがわかりにくい。この辺りは、一部記載が現在のバージョンにそぐわないものの、こちらの記事がとてもわかりやすくまとめられている。

https://qiita.com/Howasuto/items/b362991fafd8b190e260


##application(_:configurationForConnecting:options:)
Retrieves the configuration data for UIKit to use when creating a new scene.

新しい画面を作る際にUIKitが使う設定データを保持するメソッドとなります。Sceneの種類や管理するためのオブジェクト、最初に表示するViewControllerを含んだStoryboardの情報を扱います。`そのため、Main.storyboardを単純に削除すると、設定上のエラーが生じます`。初期状態では"Default Configuration"＝Main.storyboardであるからです。これはinfo.plistに設定されています。必ず実装しなければならないメソッドではなく、Main.storyboardを使わない場合はinfo.plistと合わせて外しても問題ない要素です。

この辺りは下記のまとめ記事がわかりやすいです。

https://dev.classmethod.jp/articles/ios13-appdelegate-configurationforconnecting/

##application(_:didDiscardSceneSessions:)
Tells the delegate that the user closed one or more of the app's scenes from the app switcher.

ドキュメントに書かれている通り、シーンが1つ以上閉じられたことをデリゲートに伝えるメソッドです。ここで書かれているapp switcherはアプリの切り替えに使う機能ですね。Appleのサイトにわかりやすい例がGIFで載せられています。

https://support.apple.com/ja-jp/HT202070


#SceneDelegate

こちらもプロジェクトを新規に立ち上げた際に自動的に組み込まれるファイルです。

```swift
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    //UIRespodeはクラス
    //UIWindowSceneDelegateはプロトコル

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // オプションで UIWindow `window` を設定し、提供された UIWindowScene `scene` にアタッチするには、このメソッドを使用します。
        // ストーリーボードを使用している場合、`window`プロパティは自動的に初期化され、シーンにアタッチされます。
        // このデリゲートは、接続するシーンやセッションが新しいことを意味しません（代わりに `application:configurationForConnectingSceneSession` を参照してください）。
        guard let _ = (scene as? UIWindowScene) else { return }
    }


    func sceneDidDisconnect(_ scene: UIScene) {
        // シーンがシステムから解放されるときに呼び出されます。
        // これは、シーンがバックグラウンドに入った直後や、セッションが破棄されたときに発生します。
        // 次にシーンが接続したときに再作成可能な、このシーンに関連するすべてのリソースを解放します。
        // そのセッションは必ずしも破棄されたわけではないので、シーンは後で再接続するかもしれません (代わりに `application:didDiscardSceneSessions` を参照してください)。

    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        // シーンが非アクティブな状態からアクティブな状態になったときに呼び出されます。
        // このメソッドを使用して、シーンが非アクティブだったときに一時停止していた（またはまだ開始していない）タスクを再開します。
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // シーンがアクティブな状態から非アクティブな状態に移行するときに呼び出されます。
        // これは一時的な中断（例：電話の着信）によって起こる可能性があります。
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        // シーンが背景から前景に移行するときに呼び出されます。
        // 背景に入るときに行った変更を元に戻すには、このメソッドを使います。
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        // シーンが前景から背景に移行する際に呼び出されます。
        // このメソッドを使用して、データを保存し、共有リソースを解放し、シーン固有の状態情報を十分に保存します。
        // シーンを現在の状態に戻すために十分なシーン固有の状態情報を保存します。
    }


}
```

#info.plist

info.plistは実行ファイルの構成情報を記述されており、Sceneの各種設定なども記載されているため、プロジェクト内のstoryboardを削除してもinfo.plistが残る場合に、エラーが生じる可能性があります。

https://qiita.com/ryomaDsakamoto/items/739a7a5de248e5514d8d

特にmain.storyboardを削除した場合は、info.plistの項目のうち関係するものを削除しておく必要があります。探し方としては上記の記事を参考に検索かけるのが手っ取り早いです。これはあくまでHowtoですので、下記にinfo.plistについてまとめていきます。

これがinfo.plistの初期設定画面となります。Main.storyboardに関わる点としては

>Application Scene Manifest
>-Scene Configuration
>--Application Session Role
>---Item 0(Default Configuration)
>----Configuration Name 
>----Storyboard Name

という階層のConfiguration NameとStoryboard Nameです。これらはAppDelegateのメソッドである`application(_:didFinishLaunchingWithOptions:)`で指定される Default Configuration であり、そのDefaultの設定がStoryboardではMainというわけです。

これらはMain.storyboardを必要としないのであれば消してしまっても、コードで起動時画面を設定していけば問題ありません。逆に残した状態であると正しく設定しないとエラーが生じてしまいます。試したことありませんが、正しく設定すれば、AppDelegateでログイン有無による起動時画面の切り替えも行えるかもしれません。

![スクリーンショット 2021-05-03 14.10.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560363/8c36bb18-38e6-f0fd-e4b3-c283b888f147.png)