SwiftUIの画面処理の仕方

## はじめに
SwiftUIを使用し、アプリを作成するとき、画面の処理の仕方がどうなるかを調査しました。


## 作成例
### 例
チェックをONにしたら、その項目の取り消し線を引くという例です。

![スクリーンショット 2024-02-11 16.18.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176603/60a16807-f37e-55ad-cb43-4e46a93b0fca.png)

SwiftUIにはHTMLのチェックボタンずばりはありませんでした。
ToggleというUIコンポーネントが今回使用できそうなので代わりに使用しました。

### 上記画面のソース
ソース例を記載します。
```swift
import SwiftUI

// Task構造体: タスクのデータモデルを定義。IdentifiableとEquatableプロトコルに準拠しています。
struct Task: Identifiable, Equatable {
    let id: Int // タスクの一意識別子
    var title: String // タスクのタイトル
    var checked: Bool // タスクが完了したかどうかの状態
}

// ContentView: アプリのメインビューを定義する構造体。
struct ContentView: View {
    @State private var tasks = [ // タスクの配列を管理する状態変数。@Stateにより、UIが自動的に更新されます。
        Task(id: 1, title: "散歩", checked: true),
        Task(id: 2, title: "料理", checked: false),
        Task(id: 3, title: "筋トレ", checked: true)
    ]
    
    var body: some View {
        List { // リストビューを使用して、タスクの一覧を表示。
            ForEach($tasks) { $task in // $tasksを使用して、タスク配列の各要素に対するバインディングを生成し、ListRowに渡す。
                ListRow(taskTitle: $task.title, isChecked: $task.checked) // ListRowビューを使用して、各タスクを表示。
            }
        }
    }
}

// ListRow: リストの各行を定義するビュー。タスクのタイトルとチェック状態を表示する。
struct ListRow: View {
    @Binding var taskTitle: String // タスクタイトルのバインディング。外部からの変更を受け入れる。
    @Binding var isChecked: Bool // チェック状態のバインディング。外部からの変更を受け入れる。
    
    var body: some View {
        Toggle(isOn: $isChecked) { // トグルスイッチ。isCheckedの状態に基づいてON/OFFを切り替える。
            if isChecked {
                Text(taskTitle) // タスクがチェックされている場合、タイトルに取り消し線を表示。
                    .strikethrough()
                    .fontWeight(.ultraLight)
            } else {
                Text(taskTitle) // タスクがチェックされていない場合、通常のタイトルを表示。
            }
        }
    }
}

#Preview {
    ContentView()
}
```

## 上記の動き
SwiftUIのアプローチは以下のようになりました。

- **ON/OFFの切り替えと取り消し線の表示**: `@Binding`を使用して`ListRow`ビュー内の`isChecked`状態を監視し、この状態に基づいて`Toggle`スイッチのON/OFFを反映し、条件に応じて`Text`に取り消し線を表示します。これはデータバインディングと宣言的UI記述の例です。

- **データの表示**: `@State`プロパティラッパーを使用して`ContentView`内の`tasks`配列の状態を管理し、`ForEach`を使って配列の各要素に対してループ処理を行い、データをビューにバインドします。これは状態管理と宣言的UI記述の例です。

- **画面構成**: `ContentView`と`ListRow`ビューを定義して、アプリのUIを構成します。`ContentView`がアプリのメインビューを表し、`ListRow`がリストの各行を表すコンポーネントとして機能します。これはコンポーネント化の例です。

## SwiftUIのアプローチ
SwiftUIで対応した特徴として、宣言的UI記述、状態管理、コンポーネント化、そしてデータバインディングがありました。WebのフロントのフレームワークのReactやVueに似ています。これらの概念を組み合わせることで、データの変更がUIに即座に反映され、ユーザーインタラクションを効率的に扱うことができます。
今回のアプリに当てはめると以下になります。
- **宣言的UI記述**: `ContentView`と`ListRow`のビュー定義により、UIの構造と表示ロジックが明確に宣言されています。
  
- **状態管理**: `@State`プロパティラッパーにより、UIの状態が内部的に追跡され、状態の変更に応じてUIが自動的に更新されます。

- **コンポーネント化**: `ListRow`ビューにより、再利用可能なUIコンポーネントが作成され、UIの再利用性と保守性が向上します。

- **データバインディング**: `@Binding`プロパティラッパーにより、親ビューから子ビューへのデータの双方向バインディングが実現され、UIコンポーネント間でデータが効率的に同期されます。


SwiftUIの設計思想は、宣言的UIプログラミングパラダイムに根ざしています。このアプローチは、UIの状態と表示を密接に連携させ、状態の変更が直接UIの更新に反映されるようにすることを目指しています。

- **状態の一元管理**: `@State`, `@Binding`, `@ObservedObject`などのプロパティラッパーを使用することで、アプリケーションの状態を一元管理しやすくなります。これにより、状態の変更がUIのどの部分に影響を与えるかをシステムが把握し、必要な部分のみを効率的に更新できます。

- **データフローの明確化**: データのバインディングと状態管理の仕組みにより、データがアプリケーションを通じてどのように流れるかが明確になります。これにより、バグの発生を減らし、コードの可読性と保守性を向上させることができます。

- **UIとロジックの密接な結合**: UIの構造と表示ロジックを宣言的に記述することで、UIの見た目と動作を一箇所で管理できます。これにより、開発プロセスが簡潔になり、迅速なイテレーションが可能になります。

## おわりに
Swiftの構造体、オプショナル型というSwiftに特徴的な型を踏まえた記載等も追加したかったですが、内容が広範囲になりまとまりもなくなるため割愛しました。SwiftとSwiftUIに詳しくない方々にも、これらの技術がどのように動作し、どのようなメリットを提供するのかざっくりわかれば幸いです。


## 参考記事

https://qiita.com/atsu123456789/items/682bce5cab3649363013

https://www.udemy.com/course/swiftui-ios-iphone/?utm_source=adwords&utm_medium=udemyads&utm_campaign=DSA_WebIndex_la.JA_cc.JP&utm_content=deal4584&utm_term=_._ag_89101504074_._ad_624699263400_._de_c_._dm__._pl__._ti_dsa-454026085647_._li_1009050_._pd__._&gclid=CjwKCAjwv8qkBhAnEiwAkY-ahmilHuWoL7OQRFZ3dMIu6-F-zFWlsRj16En4BE4ckq0Ga_OA7eK-RBoC2AMQAvD_BwE