【UIKitシリーズ】その2 - プロジェクトの基本的な制御フローを理解する！

[UIKitシリーズ目次はこちら](https://qiita.com/generosity_hiroto_taniguchi/items/5ab12cc1d0fa97598de6)

---
# はじめに

UIKitを使用したiOSアプリ開発を学ぶ際、多くの初心者向け教材はUIの実装方法に焦点を当てています。
しかし私は、アプリケーションの基本的な制御フローを理解することが、今後UIを自身で実装することができる重要な要素だと思います！


この記事では、UIKitを使用したiOSアプリの起動から最初の画面表示までの流れを詳しく解説します。AppDelegate、SceneDelegate、StoryboardそしてViewControllerがどのように連携して動作するのか、理解することが目標です！

# 対象読者
- UIKitでプロダクト開発したい方！
- UIKitの制御フローを把握したい方！

# 環境
- Swift version 5.10
- Xcode version 15.3

# プロジェクト作成
[前回](https://qiita.com/generosity_hiroto_taniguchi/private/90f2465011dae6941cf1)と同様に、Interface に Storyboard を選択してプロジェクトを作成します。

### 構成の確認
XCodeが提供してくれるテンプレートは、あらゆるアプリ制作の基盤として利用できます。
template を iOS app を選択した場合、最初のフォルダ構成は下記のようになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786602/2cac4aaf-36b8-f07d-bab2-fd276d15c749.png"
width="300">

各ファイルの概要は以下の通りです。

- AppDelegate.swift : アプリケーションのライフサイクルを管理
- SceneDelegate.swift : UISceneSessionのライフサイクルを管理（iOS 13以降）
- ViewController.swift : 画面のコンテンツと動作を管理
    - (補足: UIKitフレームワークで定義された、UIViewContollerを継承している。)
- Main.storyboard : ユーザーインターフェースのビジュアルレイアウト
- LaunchScreen.storyboard : アプリ起動時に表示される画面
- Assets.xcassets: 画像やアイコンなどのリソースを管理
- Info.plist : アプリの設定情報を含む

# コードの追加と動作確認
アプリの起動フローに関して詳しく説明する前に、ViewControlerにコード追加し、画面上にテキストが表示されることを確認してみます！
#### コードの追加
```:ViewController.swift
import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // ラベルのインスタンスを生成
        let label = UILabel()
        // ラベルのサイズと位置を設定
        label.frame = CGRect(x: 350, y: 100, width: 500, height: 100)
        // 表示テキスト設定
        label.text = "Hello, World!"
        // 色設定
        label.textColor = .red
        // フォントサイズ設定
        label.font = UIFont.systemFont(ofSize: 30)
        // View に UILabel を追加
        view.addSubview(label )
    }
}
```
#### 動作確認
コードを追加したので、動作を確認をしましょう！

![buid_prepare.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786602/0f2dc106-7b90-5bb4-e5c8-4246197f0dad.png)

1. build ターゲットを選択
今回は、iOS Simulators から iPhone15Pro を選択。
2. 実行
実行ボタンをクリック(または、command + R)で確認。

**結果**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786602/38d7d3e3-6df3-21ce-e65b-99cdd6eb50f6.png" alt="Create Project" width="250">

これでテンプレートの初期設定では、ViewControllerに変更を加えることで表示される内容が変わることを確認できました！

なぜ、ViewControllerを変更すると表示される内容が変わるのでしょうか？
それを理解するために、アプリの起動フローを確認しましょう！

# アプリの起動フロー
ここからは、アプリが起動してから、最初の画面が表示されるまでのフローを説明します。

1. AppDelegateがアプリケーションの起動を処理
2. SceneDelegateがUIWindowとrootViewControllerを設定
3. Main.storyboardから最初のViewControllerが読み込まれる
4. ViewControllerのviewDidLoad()メソッドが呼ばれる

各項目について、みていきましょう！
## 1. AppDelegateがアプリケーションの起動を処理
### AppDelegateの役割
アプリケーションのライフサイクルイベントを処理する役割があります。アプリの起動、バックグラウンドへの移行、終了など、重要なイベントをここで管理します。

### @ main属性
```:AppDelegate.swift
@main
class AppDelegate: UIResponder, UIApplicationDelegate {

```

AppDelegateクラスの上に ``@main``と記述されています。これはアプリケーションのエントリーポイントであること、つまり、アプリが起動するとき最初に呼び出されるのがこのクラスであることを示しています。

### SecenDelegateに遷移
```: AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    return true
}
```
application(_:didFinishLaunchingWithOptions:)メソッドで``return true``で正常にアプリ起動が完了すると、SecenDelegateに遷移します。

## 2. SceneDelegateがUIWindowとrootViewControllerを設定
### SceneDelegateの役割
アプリの個別のUIWidnow（シーン）のライフサイクルを管理します。

(シーン : アプリはマルチウィンドウをサポートするために「シーン」という概念を導入。各シーンは独立したUIWindowとViewControllerの階層を持つ)

### seceneメソッド
```:SceneDelegate
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let _ = (scene as? UIWindowScene) else { return }
}
```
このメソッドは、新しいシーンが作成される時に呼ばれます。ここで、UIWidowの設定とrootViewController(一番最初に読み込まれるUIViewControllerカスタムクラス)指定を行うことができます。ですが、コード上では rootViewController を指定するような処理は実装されていません。　

実は、コード上で実装しないでも設定することがでます。

どこでrootViewControllerを指定しているのかは、Storyboardに関わる Info.plistを確認すると分かります。

## 3. Main.storyboardから最初のViewControllerが読み込まれる
### Main.storyboardが読み込まれる理由
![info_project_init.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786602/0e9bf03a-f399-316d-29b2-4baa066d6a59.png)

![info_init.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786602/cdb303a1-c266-8d58-5e3c-f6d5671645e8.png)
 
各Info.plist の ``Main storyboard file bace name``と　``Storyboard Name`` を確認すると ``Main``となっていることが分かります。

この設定により、```SecenDelegate の Sceneメソッド```のコード上で実装されていなくても、システムがInfo.plistを参照して Main.storybaord を読み込みます。

(Main storyboard file base nameは、従来の設定で、アプリの主要なストーリーボードファイルを指定するためのものです。Storyboard Nameは、新しいシーンベースのライフサイクルシステム（iOS 13以降）で使用される設定です。同一名にすることで、どのiOSバージョンでも一番最初に呼び込まれるStoryboardを同一にできます。)

### Main.storyboard 上でrootViewControllerを設定
![main_storyboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3786602/26d75537-8aed-89d8-f8dd-d97926015d36.png)

Main.storyboard 内の ViewController をクリックして、 Attributes を Inspector上に表示します。そして、ViewController の設定項目を確認します。
``Is Initial View Controller`` にチェックマークが入っていると、``Tittle``と同名のViewControllerを参照します。空白の場合、デフォルトで``ViewController``という値になります。

これらの設定により、Main.stoaryboard が最初に参照する ViewController を呼び込むことが出来ています！

# 4. ViewControllerのviewDidLoad()メソッドが呼ばれる

呼び込まれるViewControllerは、UIViewConrollerを継承しています。
### UIViewControllerの役割
UIViewControllerは、ユーザーインターフェースの一部を管理し、そのViewのライフサイクルを制御します。
これは、画面上の要素であるUIView(テキストラベルやボタン)らの動作を管理する中心的な場所です。

### Viewのライフサイクル
viewDidLoad()メソッドは、ライフサイクルの一部です。(他、viewWillAppear・viewDidAppearなど)
ここで、今回ラベルを追加したように、UIの初期設定などを行います。






# まとめ

### 今回の制御フロー
アプリ起動
↓
SceneDelegateが画面（シーン）の設定
↓
Info.plistの設定に基づいてMain.storyboardが読み込まれる
↓
Main.storyboard内で「Is Initial View Controller」に設定されたViewControllerが最初の画面として表示
↓
ViewControllerのviewDidLoad()メソッドが実行され、画面の内容が初期化される。
↓
作成したラベル(「Hello, World!)が画面上に表示される

### 最後に
本記事では、UIKitを使用したiOSアプリケーションの起動から画面表示までの基本的な制御フローを解説しました。
この制御フローを理解することで、アプリケーションの動作の仕組みがより明確になります。

次回は、ViewControllerのライフサイクルについてより詳しく解説し、UIKitを使用したアプリ開発の理解をさらに深めていけたらと思います。

---
[次の項目] 執筆中

---
# 参考
- [UIKitの概要についての公式リファレンス](https://developer.apple.com/jp/documentation/uikit/about_app_development_with_uikit/)