【Swift/SwiftUI】 時計アプリをつくってみた。（３年ぶり２回目）

「なんか個人開発したい！」「Swift触ってた経験を腐らせたくない！」
っていう気持ちが最近盛り上がってきてたのをキッカケに、
「今ならまだ値上げ前のMacBookProの在庫がある！？よし新調するかー」みたいなこともあって
久しぶりにXcode開いてSwiftUIのお勉強始めました。

内容的には、以下記事をSwiftUIでやり直してみた感じになってます。

https://qiita.com/ydzum1123/items/a0508fb9102421e4746d


## 開発環境
MacOS Monterey 12.2.1
Xcode Version 13.4.1
Swift Version 5

## 作ったもの
シンプルなただの時計です。

<img width="300" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126315/4b15fe08-d9a4-ad1b-0399-e8a4d7eddbd1.png">

## ソース

https://github.com/yuta-yama-1123/TestClockApp

以下は一部抜粋したもの。
基本的にTextを配置していってるだけなので全体が必要であれば上のリンクから参照ください。

```swift
struct ContentView: View {
    // 表示内容の変数定義
    @State var dispYear = ""
    // ...(年月日、曜日、時分秒それぞれで定義)

    // 現在日時の取得
    @State var nowDate = Date()

    // 表示形式、タイムゾーンの定義用
    private let dateFormatterYear = DateFormatter()
    // ...(年月日、曜日、時分秒それぞれで定義)

    init() {
        // 初期設定として、各部品の表示内容を設定
        dateFormatterYear.dateFormat = "YYYY"
        dateFormatterYear.locale = Locale(identifier: "en_jp")
        // ...(年月日、曜日、時分秒それぞれで定義)
    }

    var body: some View {
        VStack {
            HStack {
                // 年
                // １秒ごとに時刻取得して表示が更新されるようにループタイマー処理
                Text(dispYear.isEmpty ? "\(dateFormatterYear.string(from: nowDate))" : dispYear)
                    .onAppear {
                        Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                            self.nowDate = Date()
                            dispYear = "\(dateFormatterYear.string(from: nowDate))"
                        }
                    }
                    .font(
                        .system(
                            size: 30,
                            weight: .light,
                            design: .rounded
                        )
                    )
                    .padding()
                // 月
                ...
            }
            HStack {
                // 日
                Text(dispDate.isEmpty ? "\(dateFormatterDate.string(from: nowDate))" : dispDate)
                    .onAppear {
                        Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                            self.nowDate = Date()
                            dispDate = "\(dateFormatterDate.string(from: nowDate))"
                        }
                    }
                        .font(
                            .system(
                                size: 40,
                                weight: .heavy,
                                design: .rounded
                            )
                        )
                        .padding()
                // 曜日
                ...
            }.padding(
                // デフォルトだと各要素の隙間が空きすぎるので、
                // 下のoffsetと合わせて、余白を詰める調整（以下、時分秒も同様）
                EdgeInsets(
                    top: 1,        // 上の余白
                    leading: 1,    // 左の余白
                    bottom: -40,     // 下の余白
                    trailing: 1    // 右の余白
                )
            )
            .offset(y: -40)
            // 時
            Text(dispHour.isEmpty ? "\(dateFormatterHour.string(from: nowDate))" : dispHour)
                .onAppear {
                    Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                        self.nowDate = Date()
                        dispHour = "\(dateFormatterHour.string(from: nowDate))"
                    }
                }
                .font(
                    .system(
                        size: 240,
                        weight: .heavy,
                        design: .rounded
                    )
                )
                .padding(
                    EdgeInsets(
                        top: 1,        // 上の余白
                        leading: 1,    // 左の余白
                        bottom: -80,     // 下の余白
                        trailing: 1    // 右の余白
                    )
                )
                .offset(y: -70)
            // 分
            ...
            // 秒
            ...
        }
    }
}
```

## はまりどころなど
#### Xcodeのシミュレータが動かないことがある。
そもそもの問題として、XcodeでiPhone系のシミュレータが動かなくて(iPadシリーズは大丈夫だったのに)
「どっか設定しないとiPhoneシミュレータ動かないのか〜？」ってハマってました。
（結局再起動したら直って、相変わらずXcodeはいろいろ問題抱えてそうだなぁ、と。）

#### 実装自体はほぼ苦労しなかった。
「これの横にこれを置きたくて、これとこれを縦に並べて、、、」
みたいなのが直感的に書けるし、コードからもその構造を把握しやすい、
っていうのが昨日今日でほんのちょっと触ってみた感想。

下記を参考にさせてもらって、時刻表示をリアルタイムに画面表示する点もすぐできたし。

リファクタリング兼ねてアップデートしたいなーと思ってるので、
冗長な書き方とかは温かい目でスルーして頂きたい。

## 参考にさせて頂いたページ

https://zenn.dev/oka_yuuji/articles/36a6ec42803a11

https://swift.hiros-dot.net/?p=856

※実機で動かしてみる手順も忘れてたので下記も

https://www.ingenious.jp/articles/howto/xcode/xcode-actual-machine-test/

https://qiita.com/nonkapibara/items/d14c796ca69c8a4e58d2